"lock(obj) { /* empty */ }" 对线程可见性的影响
Effects of "lock(obj) { /* empty */ }" on Thread Visibility
给定代码:
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);
empty lock
是否确保 result
值的线程可见性发生在线程之前,这是从线程内部设置的?
如果不是(即使是这样),考虑到先前建立的线程生命周期顺序,是否有比在此处使用 lock
更好的方法?
或者(和 Y 问题)Join
是否足以使修改后的变量在线程中可见?
它会起作用,是的,因为进入锁涉及内存屏障。您可以使用 Thread.MemoryBarrier
而不是 只是 那样做。性能几乎相同,主要是为了改进 reader.
的语义
就是说,如果您改为使用任务,整个事情就会变得容易得多,因为它们专门设计用于表示有结果的操作,并且在访问该结果时它们会处理适当的同步。您的代码可以简单地写成:
var result = Task.Run(() => DoSomeWork()).Result;
UseResultFromThread(result);
当然,如果您只是等待它完成,那么创建一个新线程来做一些工作甚至没有多大意义。到那时,您还不如让原始线程完成工作,而不用首先使用第二个线程;这大大简化了整个事情:
UseResultFromThread(DoSomeWOrk());
完成。
给定代码:
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);
empty lock
是否确保 result
值的线程可见性发生在线程之前,这是从线程内部设置的?
如果不是(即使是这样),考虑到先前建立的线程生命周期顺序,是否有比在此处使用 lock
更好的方法?
或者(和 Y 问题)Join
是否足以使修改后的变量在线程中可见?
它会起作用,是的,因为进入锁涉及内存屏障。您可以使用 Thread.MemoryBarrier
而不是 只是 那样做。性能几乎相同,主要是为了改进 reader.
就是说,如果您改为使用任务,整个事情就会变得容易得多,因为它们专门设计用于表示有结果的操作,并且在访问该结果时它们会处理适当的同步。您的代码可以简单地写成:
var result = Task.Run(() => DoSomeWork()).Result;
UseResultFromThread(result);
当然,如果您只是等待它完成,那么创建一个新线程来做一些工作甚至没有多大意义。到那时,您还不如让原始线程完成工作,而不用首先使用第二个线程;这大大简化了整个事情:
UseResultFromThread(DoSomeWOrk());
完成。