我有以下代码:
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!");
}
Run Code Online (Sandbox Code Playgroud)
程序将挂起在释放模式下,并以调试模式提供输出("完成!").
这是什么原因?
谢谢.
变量的值isComplete很可能被加载到发布版本中的寄存器中,以避免在while循环中从内存中读取值的往返.
因此,当值isComplete变为true 时,循环将不会"检测" .
您需要向编译器指出这个变量是volatile:基本上告诉系统不要根据当前线程中执行的代码做出假设,无论这个内存是否发生变化(即某些其他线程或进程可能会改变它).
有关详细信息,请参阅此SA答案:
我如何理解读取内存障碍和易失性 - StackOverflow
如果你想深入研究内存和并发性,那么这是Fabian Giesen关于多核系统中缓存一致性的优秀文章:
除非您知道自己在做什么,否则以下是使用锁定的好理由:
易失性关键字使用与锁定 - StackOverflow
这是MSDN doc Volatile.Read方法:
请注意,如果没有更详细的说明(参见上面的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!");
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
145 次 |
| 最近记录: |