EDIT. Я спрашиваю, что происходит, когда два потока одновременно получают доступ к тем же данным без правильной синхронизации (перед этим редактированием этот пункт не был явно выражен).
У меня есть вопрос об оптимизации, которые выполняются компилятором С# и компилятором JIT.
Рассмотрим следующий упрощенный пример:
class Example {
private Action _action;
private void InvokeAction() {
var local = this._action;
if (local != null) {
local();
}
}
}
Пожалуйста, проигнорируйте в примере, что чтение _action
может привести к кэшированию и устаревшему значению, поскольку нет летучего спецификатора или какой-либо другой синхронизации. Это не главное:)
Является ли компилятор (или, фактически, дрожание во время выполнения), оптимизировать назначение для локальной переменной и вместо этого дважды читать _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
с помощью параллельного присваивания.
Конечно, в этом примере такая "оптимизация" не имела бы никакого смысла, потому что было бы быстрее хранить значение в регистре и, таким образом, используя локальную переменную. Но в более сложных случаях есть ли гарантия, что это работает так, как ожидалось, без повторного чтения значения из памяти?