调试与发布C#代码

Evy*_*tar 2 c#

我有以下代码:

 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)

程序将挂起在释放模式下,并以调试模式提供输出("完成!").

这是什么原因?

谢谢.

ody*_*jii 9

变量的值isComplete很可能被加载到发布版本中的寄存器中,以避免在while循环中从内存中读取值的往返.

因此,当值isComplete变为true 时,循环将不会"检测" .

您需要向编译器指出这个变量是volatile:基本上告诉系统不要根据当前线程中执行的代码做出假设,无论这个内存是否发生变化(即某些其他线程或进程可能会改变它).

有关详细信息,请参阅此SA答案:

我如何理解读取内存障碍和易失性 - StackOverflow

如果你想深入研究内存和并发性,那么这是Fabian Giesen关于多核系统中缓存一致性的优秀文章:

缓存一致性引物

原子操作和争用

除非您知道自己在做什么,否则以下是使用锁定的好理由:

易失性关键字使用与锁定 - StackOverflow

这是MSDN doc Volatile.Read方法:

Volatile.Read方法()

请注意,如果没有更详细的说明(参见上面的SA主题或谷歌),MSDN文档中的描述可能很难转化为实际发生的情况.

以下是volatile关键字的MSDN文档:

volatile(C#参考)

在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)