多线程-了解内存障碍和易失性

时间:2019-02-18 19:28:54

标签: c# multithreading thread-safety clr memory-barriers

我正在研究著名的“坚果中的C#”之后的c#线程,并且在研究Thread.MemoryBarrier()现象时,偶然发现Why we need Thread.MemoryBarrier()?上Brian的示例时,我被吓死了。

我拥有i-7 8700K处理器和4.6.1 .NET,即使在程序中进行了以下更改,我也设法重现了该问题(程序永无止境):

class Program
{
    static bool stop = false;

    public static void Main(string[] args)
    {
        var t = new Thread(() =>
        {
            Console.WriteLine($"Thread begin");
            bool toggle = false;
            //while (true)
            while (!stop) 
            {
                if (stop)
                {
                    break;
                }
                toggle = !toggle;
            }
            Console.WriteLine($"Thread end");
        });
        t.Start();
        Thread.Sleep(1000);
        stop = true;
        Console.WriteLine($"Stop flag set. Waiting for thread to end...");
        t.Join();
        Console.ReadKey();
    }
}

因此,即使使用“如果(停止)”检查,问题也会重现,并且我理解原因。当我将“ Thread.MemoryBarrier()”放置在该检查问题之前时,该问题不会重现(至少我无法重现),并且我理解为什么。但是我不明白的是,当我改变while条件并放置“ while(true)”而不是“ while(!stop)”时,为什么问题不再重现了?它与“ while(true)”语句的特殊处理有关吗?

2 个答案:

答案 0 :(得分:1)

  

当我更改while条件并放入“ while(true)”而不是“ while(!stop)”时,为什么问题不再重现了?

该行为取决于多个因素,例如:硬件,操作系统,运行时环境...例如,在我的机器上,即使使用while (!stop)编写原始代码也无法重现该问题。而且我相信,可以在其他环境上使用while (true)重现该问题。

埃里克·利珀特(Eric Lippert)和乔恩·斯基特(Jon Skeet)指出,除非我们是该领域的真正专家(link#1link#2),否则我们不需要使用诸如Thread.MemoryBarrier之类的低级技术。可能您应该考虑在volatile声明中使用stop关键字,这样可以更明确地表达您的意图,并避免使用Thread.MemoryBarrier。甚至考虑将TaskCancellationToken一起使用,以具有取消Task的能力。

关于您的用户名,也许值得一提的是,关于.net的Eric Lippert和Jon Skeet就像是关于魔术的Gandalf

更新

在下面阅读Eric Lippert的评论。在您真正需要它们之前,不要同时使用volatileThread.MemoryBarrier

答案 1 :(得分:-1)

while (true)没什么特别的。

您的详细答案描述如下: https://msdn.microsoft.com/en-us/magazine/jj863136.aspx