Ответ 1
Речь идет не только об атомарности. Это также касается видимости памяти. Переменная может храниться в основной памяти или в кеше ЦП. Если переменная хранится только в кэше ЦП, она не будет видна для потоков, работающих на разных ЦП. Рассмотрим следующий пример:
public class Test {
private Int32 i = 5;
public void ChangeUsingAssignment() {
i = 10;
}
public void ChangeUsingInterlocked() {
Interlocked.Exchange(ref i, 10);
}
public Int32 Read() {
return Interlocked.CompareExchange(ref i, 0, 0);
}
}
Теперь, если вы вызываете "ChangeUsingAssignment" в одном потоке и "Читать" в другом потоке, возвращаемое значение может быть 5, а не 10. Но если вы вызовете ChangeUsingInterlocked, "Read" вернет 10, как ожидалось.
---------- ------------ -------------------
| CPU 1 | --> | CACHE 1 | --> | |
---------- ------------ | |
| RAM |
---------- ------------ | |
| CPU 2 | --> | CACHE 2 | --> | |
---------- ------------ -------------------
В приведенной выше диаграмме метод "ChangeUsingAssignement" может привести к тому, что значение 10 "застрянет" в CACHE 2 и не попадет в ОЗУ. Когда процессор 1 попытается прочитать его, он получит значение из ОЗУ, где он все равно 5. Использование блокировки вместо обычной записи гарантирует, что значение 10 будет полностью загружено в ОЗУ.