У вас нет синхронизации , защищающей переменную done. Когда к объекту или переменной можно получить доступ в одном потоке, в то время как другой поток изменяет или может изменить его, необходима некоторая форма синхронизации.
Есть много способов, которыми это может закончиться. Например, рассмотрим этот цикл:
private void test()
{
do
{
if (done)
{
Invoke(new setLabelMethod(setLabelValue), "yeah");
done = false;
}
Thread.Sleep(500);
} while (running);
}
Предположим, что компилятор знает, что Thread.Sleep
не изменяет done
или running
. Можно сделать вывод, что ничто в этом цикле не изменяет done
или running
(при условии, что done
является ложным при входе в цикл), и поэтому оно может кэшировать done
(и running
!) В регистрах через вызовы Thread.Sleep
.
Другими словами, он может «оптимизировать» ваш цикл до:
private void test()
{
if (done)
Invoke(new setLabelMethod(setLabelValue), "yeah");
done = false;
if (running)
while(1) Thread.Sleep(500);
}
Обратите внимание, что это добросовестная оптимизация, если значения done
и running
не изменены другими потоками. Компилятор может принять это, поскольку он нарушает правила изменения значения в одном потоке, в то время как другой поток получает или может получить к нему доступ без синхронизации, этот поток может обращаться к этим переменным, и этот код не содержит функций синхронизации.
Конечно, ваш код не должен беспокоиться об этом, если вы следуете правилам. Компилятору запрещено делать «оптимизации», которые нарушают ваш код, и вам не нужно беспокоиться о том, как он это делает. Но это применимо только если вы следуете правилу. (На практике компилятор не будет кэшировать значение в регистре при вызове функции синхронизации, а изменяемые переменные никогда не будут кэшироваться в регистрах.)