0

如果我在一个线程上创建一个变量,然后使用ManualResetEvent'sWaitOne()方法阻塞,直到另一个线程为同一个变量分配一个值并发出EventWaitHandel. 当我在第一个线程上读取变量时,我能保证总是得到另一个线程刚刚分配的值吗?

(我担心由于一些优化,我无法从 CPU 缓存中获取值,因为据我所知,我没有使用任何内存屏障)。

例如

var str = "multi-threading is hard!";
var mre = new ManualResetEvent(false);
Task.Factory.StartNew(() => 
    {
        str = Console.ReadLine();
        mre.Set();
    ));
mre.WaitOne();
Console.WriteLine(str);
4

2 回答 2

1

这些指令不会被重新排序,这意味着,在生产线程上,字段分配将始终在句柄发出信号之前发生,而在消费线程上,字段将始终在句柄发出信号后读取。

如果这两个指令对中的任何一个可以重新排序(例如,如果第二个线程可以在句柄发出信号之前读取该字段),那么您将不到正确的值。

WaitOne()引入了隐式内存屏障,为您提供所需的获取-释放语义。

Brian Gideon 和 Hans Passant 汇总了 .NET 框架中引入隐式内存屏障的几个类的一个很好的列表:内存屏障生成器

更多信息:获取和释放语义/获取和释放栅栏

于 2014-02-21T09:06:37.550 回答
0

您的变量是捕获变量,即编译器将此局部变量转换为编译器生成的类的字段,因为您在 lambda 表达式中使用它。Afaik,这些编译器生成的字段没有标记volatile,所以它们可以被缓存。

编辑:确实,该领域不是易变的。

您绝对可以通过编写自己的类来防止缓存,这样编译器就不必创建一个。但是,这当然会妨碍代码的简洁性。

于 2014-02-21T09:03:11.687 回答