Я ищу воспроизводимый пример, который может продемонстрировать, как работает volatile keyword. Я ищу что-то, что работает "неправильно", без переменных, помеченных как изменчивые, и работает "правильно" с ним.
Я имею в виду пример, который продемонстрирует, что порядок операций записи/чтения во время выполнения отличается от ожидаемого, когда переменная не помечена как изменчивая и не отличается, когда переменная не помечена как энергозависимая.
Я подумал, что у меня есть пример, но потом с помощью других я понял, что это всего лишь фрагмент неправильного многопоточного кода. Почему volatile и MemoryBarrier не препятствуют переупорядочению операций?
Я также нашел ссылку, которая демонстрирует эффект volatile в оптимизаторе, но он отличается от того, что я ищу. Он демонстрирует, что запросы к переменной, помеченной как volatile, не будут оптимизированы. Как проиллюстрировать использование ключевого слова volatile в С#
Вот где я до сих пор. Этот код не показывает никаких признаков переупорядочения операции чтения/записи. Я ищу тот, который покажет.
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;
namespace FlipFlop
{
class Program
{
//Declaring these variables
static byte a;
static byte b;
//Track a number of iteration that it took to detect operation reordering.
static long iterations = 0;
static object locker = new object();
//Indicates that operation reordering is not found yet.
static volatile bool continueTrying = true;
//Indicates that Check method should continue.
static volatile bool continueChecking = true;
static void Main(string[] args)
{
//Restarting test until able to catch reordering.
while (continueTrying)
{
iterations++;
a = 0;
b = 0;
var checker = new Task(Check);
var writter = new Task(Write);
lock (locker)
{
continueChecking = true;
checker.Start();
}
writter.Start();
checker.Wait();
writter.Wait();
}
Console.ReadKey();
}
static void Write()
{
//Writing is locked until Main will start Check() method.
lock (locker)
{
WriteInOneDirection();
WriteInOtherDirection();
//Stops spinning in the Check method.
continueChecking = false;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void WriteInOneDirection(){
a = 1;
b = 10;
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void WriteInOtherDirection()
{
b = 20;
a = 2;
}
static void Check()
{
//Spins until finds operation reordering or stopped by Write method.
while (continueChecking)
{
int tempA = a;
int tempB = b;
if (tempB == 10 && tempA == 2)
{
continueTrying = false;
Console.WriteLine("Caught when a = {0} and b = {1}", tempA, tempB);
Console.WriteLine("In " + iterations + " iterations.");
break;
}
}
}
}
}
Edit:
Как я понимаю, оптимизация, вызывающая переупорядочение, может исходить от JITer или от самого оборудования. Я могу перефразировать мой вопрос. Процессоры JITER или x86 переупорядочивают операции чтения/записи И есть ли способ продемонстрировать это на С#, если они это делают?