EDIT: Я, наконец, написал полную статью о выпуске: Synchronization, memory visibility and leaky abstractions.Net видимость памяти поведение
Я демонстрирует важность летучего чтения с этим кодом:
bool ok = false;
void F()
{
int n = 0;
while (!ok) ++n;
}
public void Run()
{
Thread thread = new Thread(F);
thread.Start();
Console.Write("Press enter to notify thread...");
Console.ReadLine();
ok = true;
Console.WriteLine("Thread notified.");
}
Как и ожидалось, нить не знает о новом значении ok
, и программа зависает.
Но для получения этого поведения я должен что-то сделать в цикле while
, например. увеличивая целое число.
Если я удалю оператор ++n
, поток прочитает новое значение и выйдет.
Я предполагаю, что это что-то делать с джиттер оптимизаций, потому что, насколько CIL обеспокоен нет ничего (по крайней мере, для неспециалиста, как я):
.method private hidebysig instance void F() cil managed
{
.maxstack 2
.locals init ([0] int32 n)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0008
IL_0004: ldloc.0
IL_0005: ldc.i4.1
IL_0006: add
IL_0007: stloc.0
IL_0008: ldarg.0
IL_0009: ldfld bool ThreadingSamples.MemoryVisibilitySample::ok
IL_000e: brfalse.s IL_0004
IL_0010: ret
}
.method private hidebysig instance void F() cil managed
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldfld bool ThreadingSamples.MemoryVisibilitySample::ok
IL_0006: brfalse.s IL_0000
IL_0008: ret
}
И, наоборот, Я бы наивно ожидал, что выполнение чего-то в цикле увеличит вероятность того, что поток инициирует обновление кеша.
Что мне еще не хватает?
FINAL EDIT: это снова некоторые джиттер черная магия.
Kudos to Hans для подтверждения этого является «хорошо известной» проблемой JITter и указывает, что в x64 мы получаем «ожидаемое» поведение.
Kudos to MagnatLU для предоставления полученного кода сборки и обмена некоторой мудростью отладки.
Это хорошо известное поведение x86 джиттера. Не произойдет, когда вы используете джиттер x64. Не имеет большого отношения к джиттеру, bool не является объектом синхронизации. –
В чем вопрос? В вашем вопросе упоминается «изменчивое чтение», но вы на самом деле этого не делаете, так что на самом деле вопрос? –
@ HansPassant: Спасибо за быстрый ответ. Действительно, в x64 поведение «правильно» без '++ n'. Больше информации о том, почему и как? Что-то общего с моделями памяти x86 и x64 или чистым CLR?PS: Пожалуйста, Ганс не предполагает, что то, что вы знаете, «хорошо известно», ваши ответы показывают, что вы знаете гораздо больше, чем средний неспециалист. ;) – Pragmateek