“lock(obj){/ * empty * /}”对线程可见性的影响

时间:2015-06-05 18:56:05

标签: c# .net multithreading thread-safety

鉴于代码:

object sync = new object();
string result = null;

var thread = new Thread(() => {
   var workResult = DoSomeWork();
   lock (sync) { result = workResult; }
});

thread.Start();
thread.Join();

lock (sync) {
   // No code in here - not 'atomic' wrt the thread
   // as the thread has been terminated and joined.
}

// Is it SAFE to access the `result` here?
UseResultFromThread(result);

为空 lock是否确保在线程内部设置result的{​​{1}}值的线程可见性之前发生过?

如果没有(即使是这样),在给定先前建立的线程生命周期排序的情况下,是否有比使用lock更好的方法?

或(和Y问题)是Join是否足以让修改后的变量的线程可见?

1 个答案:

答案 0 :(得分:5)

它会起作用,是的,因为进入锁定涉及内存屏障。您可以使用Thread.MemoryBarrier代替 这样做。性能几乎相同,主要是为了改善读者的语义。

也就是说,如果您使用任务,整个过程会变得更容易,因为它们专门用于表示具有结果的操作,并且在访问该结果时它们将负责相应的同步。您的代码可以简单地编写:

var result = Task.Run(() => DoSomeWork()).Result;
UseResultFromThread(result);

当然,如果您只是等待它完成,那么创建一个新线程来做一些工作就没有多大意义了。那时你也可以让原始线程完成工作,而不是先打扰第二个线程;这大大简化了整个事情:

UseResultFromThread(DoSomeWOrk());

完成了。