gpt4 book ai didi

c# - 为什么 volatile 和 MemoryBarrier 不阻止操作重新排序?

转载 作者:可可西里 更新时间:2023-11-01 08:09:49 25 4
gpt4 key购买 nike

如果我正确理解 volatile 和 MemoryBarrier 的含义,那么下面的程序将永远无法显示任何结果。

每次我运行它时,它都会捕获写入操作的重新排序。我在 Debug 或 Release 中运行它并不重要。将它作为 32 位或 64 位应用程序运行也没有关系。

为什么会这样?

    using System;
using System.Threading;
using System.Threading.Tasks;

namespace FlipFlop
{
class Program
{
//Declaring these variables as volatile should instruct compiler to
//flush all caches from registers into the memory.
static volatile int a;
static volatile int 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++;
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)
{
//Using memory barrier should prevent opration reordering.
a = 1;
Thread.MemoryBarrier();
b = 10;
Thread.MemoryBarrier();
b = 20;
Thread.MemoryBarrier();
a = 2;

//Stops spinning in the Check method.
continueChecking = false;
}
}

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;
}
}
}
}
}

最佳答案

你没有在测试之间清理变量,所以(除了第一个)最初 a2b20 - before Write 已完成任何

Check 可以获取 ainitial 值(所以 tempA2),然后Write就可以进去了,尽量把b改成10

现在 Check 读取 b(所以 tempB10)。

等等。无需重新订购即可重现。

在运行之间将 ab 重置为 0,我希望它会消失。

编辑:确认; “按原样”我几乎立即得到了问题(<2000 次迭代);但通过添加:

while (continueTrying)
{
a = b = 0; // reset <======= added this

然后它可以毫无问题地循环任意时间。

或者作为一个流程:

Write                   A=  B=        Check

(except first run) 2 20
int tempA = a;
a = 1; 1 20
Thread.MemoryBarrier();
b = 10; 1 10
int tempB = b;

关于c# - 为什么 volatile 和 MemoryBarrier 不阻止操作重新排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6162996/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com