为什么我们需要 Thread.MemoryBarrier()? [英] Why we need Thread.MemoryBarrier()?

查看:27
本文介绍了为什么我们需要 Thread.MemoryBarrier()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C# 4 in a Nutshell"中,作者展示了这个类有时可以在没有MemoryBarrier的情况下写0,虽然我在我的Core2Duo中无法重现:

In "C# 4 in a Nutshell", the author shows that this class can write 0 sometimes without MemoryBarrier, though I can't reproduce in my Core2Duo:

public class Foo
{
    int _answer;
    bool _complete;
    public void A()
    {
        _answer = 123;
        //Thread.MemoryBarrier();    // Barrier 1
        _complete = true;
        //Thread.MemoryBarrier();    // Barrier 2
    }
    public void B()
    {
        //Thread.MemoryBarrier();    // Barrier 3
        if (_complete)
        {
            //Thread.MemoryBarrier();       // Barrier 4
            Console.WriteLine(_answer);
        }
    }
}

private static void ThreadInverteOrdemComandos()
{
    Foo obj = new Foo();

    Task.Factory.StartNew(obj.A);
    Task.Factory.StartNew(obj.B);

    Thread.Sleep(10);
}

这种需求对我来说似乎很疯狂.我如何识别所有可能发生的情况?我认为如果处理器改变操作顺序,它需要保证行为不会改变.

This need seems crazy to me. How can I recognize all possible cases that this can occur? I think that if processor changes order of operations, it needs to guarantee that the behavior doesn't change.

你介意使用 Barriers 吗?

Do you bother to use Barriers?

推荐答案

您将很难重现此错误.事实上,我什至会说您将永远无法使用 .NET Framework 重现它.原因是 Microsoft 的实现使用强内存模型进行写入.这意味着写入被视为易失性.易失性写入具有锁释放语义,这意味着所有先前的写入必须在当前写入之前提交.

You are going to have a very hard time reproducing this bug. In fact, I would go as far as saying you will never be able to reproduce it using the .NET Framework. The reason is because Microsoft's implementation uses a strong memory model for writes. That means writes are treated as if they were volatile. A volatile write has lock-release semantics which means that all prior writes must be committed before the current write.

然而,ECMA 规范具有较弱的内存模型.因此,理论上有可能 Mono 甚至 .NET Framework 的未来版本可能会开始表现出这种错误行为.

However, the ECMA specification has a weaker memory model. So it is theoretically possible that Mono or even a future version of the .NET Framework might start exhibiting the buggy behavior.

所以我要说的是,消除障碍 #1 和 #2 不太可能对程序的行为产生任何影响.当然,这不是保证,而是仅基于 CLR 的当前实现的观察.

So what I am saying is that it is very unlikely that removing barriers #1 and #2 will have any impact on the behavior of the program. That, of course, is not a guarantee, but an observation based on the current implementation of the CLR only.

移除障碍 #3 和 #4 肯定会产生影响.这实际上很容易重现.好吧,不是这个例子本身,但下面的代码是最著名的演示之一.它必须使用发布版本进行编译并在调试器之外运行.错误是程序没有结束.您可以通过在 while 循环内调用 Thread.MemoryBarrier 或将 stop 标记为 volatile 来修复该错误>.

Removing barriers #3 and #4 will definitely have an impact. This is actually pretty easy to reproduce. Well, not this example per se, but the following code is one of the more well known demonstrations. It has to be compiled using the Release build and ran outside of the debugger. The bug is that the program does not end. You can fix the bug by placing a call to Thread.MemoryBarrier inside the while loop or by marking stop as volatile.

class Program
{
    static bool stop = false;

    public static void Main(string[] args)
    {
        var t = new Thread(() =>
        {
            Console.WriteLine("thread begin");
            bool toggle = false;
            while (!stop)
            {
                toggle = !toggle;
            }
            Console.WriteLine("thread end");
        });
        t.Start();
        Thread.Sleep(1000);
        stop = true;
        Console.WriteLine("stop = true");
        Console.WriteLine("waiting...");
        t.Join();
    }
}

某些线程错误之所以难以重现,是因为您用来模拟线程交错的相同策略实际上可以修复错误.Thread.Sleep 是最显着的例子,因为它会产生内存屏障.您可以通过在 while 循环内调用并观察错误消失来验证这一点.

The reason why some threading bugs are hard to reproduce is because the same tactics you use to simulate thread interleaving can actually fix the bug. Thread.Sleep is the most notable example because it generates memory barriers. You can verify that by placing a call inside the while loop and observing that the bug goes away.

您可以在此处查看我的回答以进行另一项分析您引用的书中的示例.

You can see my answer here for another analysis of the example from the book you cited.

这篇关于为什么我们需要 Thread.MemoryBarrier()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆