繁体   English   中英

如果我调用Thread.Join(),我是否需要volatile?

[英]Do I need volatile if I call Thread.Join()?

在Java中,如果只在加入突变它的线程后才访问它,则字段不需要是volatile; 联接在关系之前强制执行。

在c#怎么样? 使用下面的代码,我保证在调用Join()之后会看到_value的更新值,或者我是否需要使_value变为volatile?

private String _value = "FOO"

public void Foo() 
{

   Thread myThread = new Thread(Bar);
   myThread.Start();
   myThread.Join();
   Console.WriteLine("[Main Thread] _val = "+ _value);

}

public void Bar()
{

   for(int i=0; i<1000; i++)
   {
         Console.WriteLine("Looping");

         if(i==75) 
         {
             _value="BAR";
         }
   }
   Console.WriteLine("DONE Looping");
}

在我的代码片段中,是否会打印“BAR”?

首先:我的一般经验法则是,如果我问的问题是“这是否需要波动?” 那时我不太了解内存模型,不足以编写低锁代码。

只需将物品置于锁定之下,如果没有非常好的理由和专家的建议,请不要尝试低锁定代码。

我不是这样的专家。 我不太了解C#内存模型来编写低锁代码,如果在弱内存模型硬件上运行它将是正确的。

要解决您的实际问题:

我保证在调用Join()之后会看到_value的更新值,还是需要使_value变为volatile?

您的问题的答案在C#规范中,为方便起见,我在此引用:

执行C#程序,以便在关键执行点保留每个执行线程的副作用。 副作用定义为易失性字段的读取或写入,对非易失性变量的写入,对外部资源的写入以及抛出异常。 必须保留这些副作用的顺序的关键执行点是对volatile字段,锁定语句以及线程创建和终止的引用。

您有一个非易失性变量的写入,并且该线程在连接返回时结束,因此必须在连接点保留写入的副作用。

通用线程同步操作执行完整的内存屏障。 肯定是开始和加入并结束一个线程。 没有这些,各种程序都会出现故障。

这些保证通常没有记录,但实际上很明显。 唉,我不能提供确凿的证据,除非说其他任何东西都会疯狂。

将此列表视为未充分记录的证据,并且您正在寻找的属性很可能成立。

在我的代码片段中,是否会打印“BAR”?

是。 我相信所有专家都会就此达成一致。 这是一个更简单的代码示例,它提出了相同的观点:

int x = 0;
Thread myThread = new Thread(() => x = 1);
myThread.Start();
myThread.Join();
x = 2;
Console.WriteLine(x); //Prints 2 because of memory barriers on exit and on Join.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM