РЕДАКТИРОВАТЬ : Я спрашиваю, что происходит, когда два потока одновременно обращаются к одним и тем же данным без надлежащей синхронизации (до этого редактирования эта точка не была четко выражена).
У меня есть вопрос об оптимизации, выполняемой компилятором C # и JIT-компилятором.
Рассмотрим следующий упрощенный пример:
class Example {
private Action _action;
private void InvokeAction() {
var local = this._action;
if (local != null) {
local();
}
}
}
Пожалуйста, игнорируйте в примере, что чтение _action
может привести к кэшированному и устаревшему значению, поскольку нет ни volatile-спецификатора, ни какой-либо другой синхронизации. Дело не в этом :)
Разрешено ли компилятору (или фактически джиттеру во время выполнения) оптимизировать присвоение локальной переменной и вместо этого читать _action
из памяти дважды:
class Example {
private Action _action;
private void InvokeAction() {
if (this._action != null) {
this._action(); // might be set to null by an other thread.
}
}
}
, который может выдать NullReferenceException
, если для поля _action
установлено одновременное присваивание null
.
Конечно, в этом примере такая «оптимизация» не имела бы никакого смысла, поскольку было бы быстрее сохранить значение в регистре и, таким образом, использовать локальную переменную. Но в более сложных случаях, есть ли гарантия, что это работает, как и ожидалось, без повторного чтения значения из памяти?