Quando usar volátil para neutralizar otimizações de compilador em C #
Passei um número extenso de semanas fazendo codificação multithread no C # 4.0. No entanto, há uma pergunta que permanece sem resposta para mi
Entendo que a palavra-chave volátil impede que o compilador armazene variáveis nos registros, evitando assim a leitura inadvertida de valores obsoletos. As gravações são sempre voláteis no .Net, portanto, qualquer documentação afirmando que também evita gravações em stales é redundant
Eu também sei que a otimização do compilador é um pouco "imprevisível". O código a seguir ilustrará uma paralisação devido a uma otimização do compilador (ao executar a compilação do release fora do VS):
class Test
{
public struct Data
{
public int _loop;
}
public static Data data;
public static void Main()
{
data._loop = 1;
Test test1 = new Test();
new Thread(() =>
{
data._loop = 0;
}
).Start();
do
{
if (data._loop != 1)
{
break;
}
//Thread.Yield();
} while (true);
// will never terminate
}
}
O código se comporta conforme o esperado. No entanto, se eu descomentar o //Thread.Yield (); linha, o loop sairá.
Além disso, se eu colocar uma instrução Sleep antes do loop, ela será encerrada. Eu não entendo.
aturalmente, decorar _loop com volátil também fará com que o loop saia (no padrão mostrado
Minha pergunta é: Quais são as regras que o complier segue para determinar quando implicitamente executar uma leitura volátil? E por que ainda posso fazer o loop sair com o que considero medidas estranhas?
EDITA
IL para o código mostrado (paralisações):
L_0038: ldsflda valuetype ConsoleApplication1.Test/Data ConsoleApplication1.Test::data
L_003d: ldfld int32 ConsoleApplication1.Test/Data::_loop
L_0042: ldc.i4.1
L_0043: beq.s L_0038
L_0045: ret
IL com Yield () (não trava):
L_0038: ldsflda valuetype ConsoleApplication1.Test/Data ConsoleApplication1.Test::data
L_003d: ldfld int32 ConsoleApplication1.Test/Data::_loop
L_0042: ldc.i4.1
L_0043: beq.s L_0046
L_0045: ret
L_0046: call bool [mscorlib]System.Threading.Thread::Yield()
L_004b: pop
L_004c: br.s L_0038