Czy dostęp do pola bool jest atomowy w języku C #? W szczególności, czy muszę założyć blokadę:
class Foo
{
private bool _bar;
//... in some function on any thread (or many threads)
_bar = true;
//... same for a read
if (_bar) { ... }
}
Odpowiedzi:
Tak.
zgodnie ze specyfikacją języka C # .
Edycja: prawdopodobnie warto również zrozumieć niestabilne słowo kluczowe.
źródło
Interlocked.Add(ref myInt);
np.?i++
jest równei=i+1
, co oznacza, że wykonujesz atomowy odczyt, następnie dodanie, a następnie atomowy zapis. Inny wątek mógłby się zmienići
po odczycie, ale przed zapisem. Na przykład dwa wątki działającei++
jednocześnie na tym samym i mogą odczytać w tym samym czasie (i tym samym odczytać tę samą wartość), dodać jeden do niego, a następnie oba zapisują tę samą wartość, skutecznie dodając tylko raz. Zablokowane. Dodaj zapobiega temu. Zasadniczo fakt, że typ jest atomowy, jest przydatny tylko wtedy, gdy jest zapisany tylko jeden wątek, ale wiele wątków odczytuje.Jak wspomniano powyżej, bool jest atomowy, ale nadal musisz pamiętać, że zależy to również od tego, co chcesz z nim zrobić.
if(b == false) { //do something }
nie jest operacją niepodzielną, co oznacza, że wartość b może się zmienić, zanim bieżący wątek wykona kod po instrukcji if.
źródło
Dostępy bool są rzeczywiście atomowe, ale to nie wszystko.
Nie musisz się martwić o odczytanie wartości, która jest „niekompletnie zapisana” - nie jest jasne, co to może oznaczać dla bool w każdym przypadku - ale musisz się martwić o pamięć podręczną procesora, przynajmniej jeśli szczegóły czas są problemem. Jeśli wątek # 1 działający na rdzeniu A ma twój
_bar
w pamięci podręcznej i_bar
zostanie zaktualizowany przez wątek # 2 działający na innym rdzeniu, wątek # 1 nie zobaczy zmiany natychmiast, chyba że dodasz blokowanie, zadeklarujesz_bar
jakovolatile
lub jawnie wstawisz wywołaniaThread.MemoryBarrier()
do unieważnienia wartość w pamięci podręcznej.źródło
var fatObject = new FatObject(); Thread.MemoryBarrier(); _sharedRefToFat = fatObject;
podejście, którego użyłem i uważam, że jest poprawne, to
volatile bool b = false; .. rarely signal an update with a large state change... lock b_lock { b = true; //other; } ... another thread ... if(b) { lock b_lock { if(b) { //other stuff b = false; } } }
celem było po prostu uniknięcie konieczności ciągłego blokowania obiektu w każdej iteracji, tylko po to, aby sprawdzić, czy musimy go zablokować, aby zapewnić dużą ilość informacji o zmianie stanu, która występuje rzadko. Myślę, że to podejście działa. A jeśli wymagana jest absolutna spójność, myślę, że zmienna byłaby odpowiednia na b bool.
źródło
lock()
, nie potrzebujeszvolatile
.