问题描述
如果我理解的意思挥发和MemoryBarrier比正确的程序如下从来没有要能表现出任何结果。
它捉住我每次运行时写操作的重新排序。没关系,如果我在调试或发布运行。这也没关系,如果我运行它作为32位或64位的应用程序。
为什么会发生?
使用系统;
使用的System.Threading;
使用System.Threading.Tasks;
命名空间触发器
{
类节目
{
//声明这些变量的波动应指示编译器
//刷新从寄存器中的所有高速缓存到内存中。
静态挥发INT一个;
静态挥发INT B:
//跟踪一些迭代,它采取了检测操作重新排序。
静态长迭代= 0;
静态对象更衣室=新的对象();
//表示操作重新排序暂时还没有发现。
静态挥发布尔continueTrying = TRUE;
//表示检查方法应继续下去。
静态挥发布尔continueChecking = TRUE;
静态无效的主要(字串[] args)
{
//重新开始测试,直到能够赶上重新排序。
而(continueTrying)
{
迭代++;
VAR检查=新任务(检查);
VAR writter =新的任务(写);
锁(更衣室)
{
continueChecking = TRUE;
checker.Start();
}
writter.Start();
checker.Wait();
writter.Wait();
}
Console.ReadKey();
}
静态无效的write()
{
//写被锁定,直到主开始检查()方法。
锁(更衣室)
{
//使用内存屏障应该prevent调度研究重新排序。
一个= 1;
Thread.MemoryBarrier();
B = 10;
Thread.MemoryBarrier();
B = 20;
Thread.MemoryBarrier();
一个= 2;
//停止旋转的检查方法。
continueChecking = FALSE;
}
}
静态无效的检查()
{
//产品转速直到发现操作重新排序或Write方法停止。
而(continueChecking)
{
INT TEMPA =一个;
b INT tempB =;
如果(tempB == 10安培;&安培; TEMPA == 2)
{
continueTrying = FALSE;
Console.WriteLine(中招当a = {0}和b = {1},TEMPA,tempB);
Console.WriteLine(在+ +迭代反复。);
打破;
}
}
}
}
}
我不认为这是重新排序。
这一块code是根本就不是线程安全的:
而(continueChecking)
{
INT TEMPA =一个;
b INT tempB =;
...
我觉得这种情况是可能的:
-
INT TEMPA =一;
执行与最后一个循环(一== 2)的值 - 有一个上下文切换到写线程
-
B = 10
和循环停止 - 有一个上下文切换到检查线程
-
INT tempB = B;
用b ==执行10
我注意到调用MemoryBarrier()加强本方案的机会。大概是因为它们会导致更多的上下文切换。
If I understand meaning of volatile and MemoryBarrier correctly than the program below has never to be able to show any result.
It catches reordering of write operations every time I run it. It does not matter if I run it in Debug or Release. It also does not matter if I run it as 32bit or 64bit application.
Why does it happen?
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;
}
}
}
}
}
I don't think this is re-ordering.
This piece of code is simply not thread-safe:
while (continueChecking)
{
int tempA = a;
int tempB = b;
...
I think this scenario is possible:
int tempA = a;
executes with the values of the last loop (a == 2)- There is a context switch to the Write thread
b = 10
and the loop stops- There is a context switch to the Check thread
int tempB = b;
executes with b == 10
I notice that the calls to MemoryBarrier() enhance the chances of this scenario. Probably because they cause more context-switching.
这篇关于为什么不稳定,MemoryBarrier并不prevent操作重新排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!