Является ли доступ к полю bool атомарным в C #? В частности, мне нужно поставить блокировку:
class Foo
{
private bool _bar;
//... in some function on any thread (or many threads)
_bar = true;
//... same for a read
if (_bar) { ... }
}
Ответы:
Да.
как указано в Спецификации языка C # .
Изменить: вероятно, также стоит понять ключевое слово volatile .
источник
Interlocked.Add(ref myInt);
например,?i++
равноi=i+1
, что означает, что вы выполняете атомарное чтение, затем сложение, а затем атомарную запись. Другой поток может изменитьсяi
после чтения, но до записи. Например, два потока, выполняющиеi++
одновременно один и тот же i, могут одновременно читать (и, таким образом, читать одно и то же значение), добавлять к нему одно, а затем оба записывать одно и то же значение, фактически добавляя только один раз. Interlocked.Add предотвращает это. Как правило, тот факт, что тип является атомарным, полезен только в том случае, если есть только один поток записи, но много потоков чтения.Как указано выше, bool является атомарным, но вам все равно нужно помнить, что он также зависит от того, что вы хотите с ним делать.
if(b == false) { //do something }
не является атомарной операцией, что означает, что значение b может измениться до того, как текущий поток выполнит код после оператора if.
источник
Доступ к bool действительно атомарен, но это еще не все.
Вам не нужно беспокоиться о чтении значения, которое `` не полностью написано '' - в любом случае не ясно, что это может означать для bool - но вам нужно беспокоиться о кешах процессора, по крайней мере, если детали время является проблемой. Если поток № 1, работающий на ядре A, имеет ваш
_bar
в кеше и_bar
обновляется потоком № 2, запущенным на другом ядре, поток № 1 не увидит изменения сразу, если вы не добавите блокировку, не объявите_bar
какvolatile
или явно не вставите вызовыThread.MemoryBarrier()
для аннулирования кешированное значение.источник
var fatObject = new FatObject(); Thread.MemoryBarrier(); _sharedRefToFat = fatObject;
подход, который я использовал и считаю правильным,
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; } } }
Основная цель заключалась в том, чтобы избежать многократной блокировки объекта на каждой итерации, чтобы проверить, нужно ли блокировать его, чтобы предоставить большой объем информации об изменении состояния, что происходит редко. Я думаю , что этот подход работает. И если требуется абсолютная согласованность, я думаю , что volatile будет уместным для b bool.
источник
lock()
, то и не надоvolatile
.