我有以下代码:
public static void Main(string[] args)
{
bool isComplete = false;
var t = new Thread(() =>
{
int i = 0;
while (!isComplete) i += 0;
});
t.Start();
Thread.Sleep(500);
isComplete = true;
t.Join();
Console.WriteLine("complete!");
}
程序将在释放模式下挂起,并以调试模式提供输出(“完成!”)。
这是什么原因?
感谢。
答案 0 :(得分:9)
变量isComplete
的值很可能被加载到发布版本中的寄存器中,以避免在while循环中从内存中读取值的往返。
因此,当isComplete
的值更改为true时,循环将不会“检测”。
你需要向编译器指出这个变量是volatile
:基本上告诉系统不根据当前线程中执行的代码做出假设,无论这个内存是否发生变化(即,某些其他线程或进程可能会改变它。)
有关详细信息,请参阅此SA答案:
How do I Understand Read Memory Barriers and Volatile - StackOverflow
如果你想深入研究内存和并发性,那么这是Fabian Giesen关于多核系统中缓存一致性的优秀文章:
Atomic operations and contention
除非你知道自己在做什么,否则以下是你应该使用锁的好理由:
Volatile keyword usage vs Lock - StackOverflow
以下是Volatile.Read
方法的MSDN文档:
请注意,如果没有这些术语的更详细解释(请参阅上面的SA主题或谷歌),MSDN文档中的描述很难转化为实际发生的内容。
以下是volatile
关键字的MSDN文档:
在C#中,这个关键字将使用半栅栏(据我所知);例如,你也可以在C中找到这个关键字,但它只影响编译器优化(不插入内存屏障),因为它最初用于读取内存映射的I / O.
示例强>:
bool isComplete = false;
var t = new Thread(() =>
{
int i = 0;
while (!Volatile.Read(ref isComplete)) i += 0;
});
t.Start();
Thread.Sleep(500);
isComplete = true;
t.Join();
Console.WriteLine("complete!");