通常认为(我相信!)
提出了一个很好的评论在这里提出,质疑如果代码执行
更简单地说:在
查看反射器,
所讨论的情况是:
很明显我可以直接将其设为
lock
会强制重新加载字段中的任何值(本质上充当内存屏障或栅栏-在这个领域中我的术语有点宽松,恐怕),因此仅在lock
内部访问的字段本身不需要是volatile
。(如果我已经错了,请说!)提出了一个很好的评论在这里提出,质疑如果代码执行
Wait()
是否同样适用-即一旦它被Pulse()
d,它会从内存中重新加载字段,还是可能在寄存器(等等)中。更简单地说:在
Wait()
之后恢复时,字段是否需要是volatile
以确保获取当前值?查看反射器,
Wait
调用ObjWait
,它是managed internalcall
(与Enter
相同)。所讨论的情况是:
bool closing;
public bool TryDequeue(out T value) {
lock (queue) { // arbitrary lock-object (a private readonly ref-type)
while (queue.Count == 0) {
if (closing) { // <==== (2) access field here
value = default(T);
return false;
}
Monitor.Wait(queue); // <==== (1) waits here
}
...blah do something with the head of the queue
}
}
很明显我可以直接将其设为
volatile
,或者将其移出来,这样每次被脉冲时都会退出并重新进入Monitor
,但我很好奇是否有必要这样做。
volatile
在x86上很重要的例子:https://dev59.com/lHRB5IYBdhLWcg3w9Lvn#458193 - Marc GravellTryDequeue
将无法通知调用者有关关闭的信息(例如,工作线程将继续工作)。所以也许应该是while (!closing && queue.Count == 0) Monitor.Wait(queue)
,然后在循环外重新检查closing
。 - Daniel EarwickerClose()
来停止排空,因此这是可以预料的;如果队列关闭,Enqueue
可以轻松修改以抛出异常。 - Marc Gravell