[英]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.