难道Monitor.Wait确保字段是重读?

人们普遍认为(我相信!),一个lock将迫使任何值从字段重新加载(基本上充当内存屏障或栅栏-我在这方面的术语变得有点松,我怕),与结果是被一个内只访问lock本身并不需要是volatile

(如果我错了已经,只是说!)

一个很好的注释就是在这里长大,质疑是否也是同样的道理,如果代码执行一个Wait() -即一旦它已经Pulse()研发,将它重新加载内存领域,或者他们能在一个寄存器(等)。

或者更简单地说:的确领域需要是volatile一后恢复时,确保已获得的电流值Wait()

看着反射器, Wait下行呼叫到ObjWait这是managed internalcallEnter )。

有问题的情形是:

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每次得到脉冲的时间,但我很好奇要知道这两个必要的。

--------------解决方案-------------

由于Wait()方法释放并重新获取的Monitor锁,如果lock进行存储栅栏语义,然后Monitor.Wait()的意志为好。

怀着希望去解决您的评论:

的锁定行为Monitor.Wait()是在文档(http://msdn.microsoft.com/en-us/library/aa332339.aspx),加上强调:

当一个线程调用wait,它释放对象的锁 ,进入对象的等待队列。 在对象的就绪队列中的下一个线程(如果有)获得锁和独占使用该对象。 调用所有线程Wait留在排队等候,直到他们收到脉冲或PulseAll通过锁定的所有者发送。 如果Pulse被发送,只有在等待队列的头部的螺纹会受到影响。 如果PulseAll发送,正在等待的对象的所有线程都受影响。 当接收到信号时,一个或多个线程离开等待队列和进入就绪队列。 在就绪队列中的线程被允许重新获取锁。

此方法返回时调用线程重新获取对象的锁

如果你问一个是否参考lock /后天Monitor意味着内存屏障,ECMA CLI规范说以下内容:

12.6.5锁和主题:

获取锁System.Threading.Monitor.Enter或进入一个synchronized方法)将隐式执行挥发性的读操作,并释放锁System.Threading.Monitor.Exit或离开一个synchronized方法)将隐式执行挥发性的写操作。 见§12.6.7。

12.6.7挥发性读取和写入:

挥发性读了“收购语义”,这意味着在读的保证之前,内存中的CIL指令序列读取指令之后发生的任何引用发生。 挥发性写有“释放语义”,意思是写保证发生后,之前在CIL指令序列的写指令的任何内存引用。

此外,这些博客文章有一些细节可能会感兴趣:

  • http://blogs.msdn.com/jaredpar/archive/2008/01/17/clr-memory-model.aspx
  • http://msdn.microsoft.com/msdnmag/issues/05/10/MemoryModels/
  • http://www.bluebytesoftware.com/blog/2007/11/10/CLR20MemoryModel.aspx

继迈克尔·伯尔的回答,不仅Wait释放并重新获取锁,但它确实这让另一个线程可以以检查共享状态,并呼吁采取了锁Pulse 。 如果第二个线程不取出锁,然后Pulse会抛出。 如果他们不Pulse第一个线程的Wait将不会返回。 因此,为了共享状态的任何其他线程的访问必须的适当存储器-barried方案中发生。

所以假设Monitor方法是根据本地辨认规则被使用,那么所有的存储器访问发生的锁内,因此只在自动存储器屏障支撑的lock是相关的/必要的。

也许我可以帮助的,而不是用你这一次...... volatile可以使用Interlocked.Exchange一个整数。

if (closing==1) { // <==== (2) access field here
value = default(T);
return false;
}

// somewhere else in your code:
Interlocked.Exchange(ref closing, 1);

Interlocked.Exchange是一个同步机制, volatile是不是...我希望这是值得的东西(但你可能已经想到这个问题)。

分类:C# 时间:2015-03-15 人气:0
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 0.888 (s). 10 q(s)