Bariera pamięci za pomocą polecenia lock

[7]}czytałem ostatnio o barierach pamięci i problemie zmiany kolejności i teraz mam pewne zamieszanie co do tego.

Rozważ następujący scenariusz:

private object _object1 = null;    
private object _object2 = null;
private bool _usingObject1 = false;

private object MyObject
{
    get 
    {
        if (_usingObject1)
        {
            return _object1;
        }
        else
        {
            return _object2;
        }
    }
    set 
    {
        if (_usingObject1)
        {
           _object1 = value;
        }
        else
        {
           _object2 = value;
        }
    }
}

private void Update()
{
    _usingMethod1 = true;
    SomeProperty = FooMethod();
    //..
    _usingMethod1 = false;
}
  1. Metoda at Update; czy Instrukcja _usingMethod1 = true jest zawsze wykonywana przed pobraniem lub ustawieniem właściwości? czy z powodu zmiany kolejności nie możemy tego zagwarantować?

  2. Czy powinniśmy używać volatile Jak

    private volatile bool _usingMethod1 = false;
    
  3. Jeśli użyjemy lock; Czy możemy zagwarantować, to każda wypowiedź wewnątrz blokady będzie wykonane w kolejności jak:

    private void FooMethod()
    {
        object locker = new object();
        lock (locker)
        {
            x = 1;
            y = a;
            i++;
        }
    }
    
Author: trooper, 2010-05-16

2 answers

Temat barier pamięci jest dość złożony. Od czasu do czasu nawet podskakuje ekspertom. Kiedy mówimy o barierze pamięci, naprawdę łączymy dwa różne pomysły.

  • Acquire fence: bariera pamięci, w której inne odczyty i zapisy nie mogą się poruszać przed ogrodzeniem.
  • Release fence: bariera pamięci, w której inne odczyty i zapisy nie mogą się poruszać po ogrodzeniu.

Bariera pamięci, która tworzy tylko jedną z dwa nazywa się czasem Half-fence . Bariera pamięci, która tworzy oba elementy, nazywana jest czasem pełnym ogrodzeniem .

Słowo kluczowe volatile tworzy pół-ogrodzenia. Odczyt pól lotnych nabiera semantyki, podczas gdy zapis ma semantykę release. Oznacza to, że żadna Instrukcja nie może być przenoszona przed odczytem lub po zapisie.

Słowo kluczowe lock tworzy pełne ogrodzenia na obu granicach(wejście i wyjście). Oznacza to, że żadna Instrukcja nie może być przenoszona przed lub po każdej granica.

Jednak wszystko to jest dyskusyjne, Jeśli chodzi o tylko jeden wątek. Porządek, jak to postrzega ten wątek, jest zawsze zachowany. W rzeczywistości, bez tej fundamentalnej gwarancji żaden program nigdy nie będzie działał poprawnie. Prawdziwym problemem jest to, jak Inne wątki postrzegają czytanie i pisanie. I tu musisz się martwić.

Więc odpowiadając na twoje pytania:

  1. Z perspektywy jednego wątku...tak. Z innego wątku perspective...no.

  2. To zależy. To może zadziałać, ale muszę lepiej zrozumieć, co próbujesz osiągnąć.

  3. Z innego wątku perspective...no. odczyty i zapisy mogą swobodnie poruszać się w granicach blokady. Nie mogą po prostu wyjść poza te granice. Dlatego ważne jest, aby inne wątki również tworzyły bariery pamięci.

 28
Author: Brian Gideon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-16 23:15:55

Słowo kluczowe volatile niczego tu nie osiąga. Ma bardzo słabe gwarancje, nie implikuje bariery pamięci. Twój kod nie pokazuje kolejnego wątku, który zostanie utworzony, więc trudno zgadnąć, czy wymagane jest blokowanie. Jest jednak trudnym wymogiem, jeśli dwa wątki mogą wykonać Update () w tym samym czasie i użyć tego samego obiektu.

Uważaj, aby Twój kod blokady nie blokuje niczego. Każdy wątek miałby własną instancję obiektu "locker". Musisz to zrobić. prywatne pole twojej klasy, utworzone przez konstruktor lub inicjalizator. Tak więc:

private object locker = new object();

private void Update()
{
    lock (locker)
    {
        _usingMethod1 = true;
        SomeProperty = FooMethod();
        //..
        _usingMethod1 = false;
    }
}

Zauważ, że będzie również wyścig na SomeProperty zadanie.

 4
Author: Hans Passant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-16 17:44:34