【问题标题】:Multithreading - Understanding memory barriers and volatile多线程 - 了解内存屏障和易失性
【发布时间】:2019-02-18 19:28:53
【问题描述】:

我正在研究 C# 线程,遵循著名的“C# in a Nutshell”,在调查 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)”语句的特殊处理有关?

【问题讨论】:

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


    【解决方案1】:

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

    行为取决于几个因素,例如:硬件、操作系统、运行时环境...例如,在我的机器上,即使使用带有while (!stop) 的原始代码也不会重现问题。而且我相信,可以在另一个环境中使用while (true) 重现该问题。

    Eric Lippert 和 Jon Skeet 表示我们不需要使用像 Thread.MemoryBarrier 这样的低级技术,除非我们是该领域的真正专家(link#1link#2)。可能,您应该考虑使用 volatile 关键字和 stop 声明,它更明确地表达了您的意图并让您不要使用 Thread.MemoryBarrier。或者甚至考虑使用TaskCancellationToken 来取消Task

    查看您的用户名可能值得注意的是,Eric Lippert 和 Jon Skeet 关于 .net 就像 Gandalf 关于魔法

    更新

    阅读下面的 Eric Lippert 的 cmets。在您真正需要之前,不要使用volatileThread.MemoryBarrier

    【讨论】:

    • 感谢您的支持;给你一些有趣的事实。首先,我没有足够的知识知道何时使用易失性与内存屏障等等。我不是这方面的专家;我的专家是知道这对我来说太复杂了,无法正确处理。这就是为什么我告诉人们只要拿出一把锁。如果您的应用程序需要性能,以至于非竞争锁太昂贵,您应该聘请纳米级优化专家。其次,我在 Commodore 64 BBS 上的别名是“Radagast”。 :-)
    • 谢谢,尤其是第二个事实。我对此几乎是准确的:) 我读过你的article about volatility,很明显volatile 对我们来说并不那么明显(非该领域的专家)。因此,即使在这种基本情况下,您是否建议不要像我在答案中建议的那样使用volatile
    • 我的建议是:如果你使用volatile,那是因为你正在做一些超级危险的事情:在没有锁的情况下修改两个线程上的内存。你有一个满是厨师的厨房,你在他们使用刀具的时候试图玩弄他们的刀;稍有不慎就会有人被砍。您最好确切地知道为什么volatile 是正确的,以及对正确性和性能的影响。但我怀疑很多人使用 volatile,因为互联网上有人告诉他们,如果他们这样做,他们的线程性能问题将免费消失。
    • 嗨,阿尔伯特。谢谢您的答复。我还要感谢 Eric 提供的诚实实用的建议。
    【解决方案2】:

    while (true) 没有什么特别之处。

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

    【讨论】:

    • 在当前状态下,这是一个仅链接答案,我们希望在 Stack Overflow 上避免这种情况。请将引用页面中的一些详细信息添加到答案帖子中。
    • 尼克,谢谢。我可以接受任何可以让我学习新东西的好链接。
    猜你喜欢
    • 2010-12-19
    • 2019-11-09
    • 1970-01-01
    • 2018-02-28
    • 2017-01-17
    • 1970-01-01
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    相关资源
    最近更新 更多