写一个锁是否保证在另一个线程中读取新内容? (.Net,内存模型)
假设我有一个属性,其setter受锁保护,但没有任何锁定在getter周围,例如
private long _myField; public long MyProperty { get { return _myField; } set { lock(whatever) _myField = value; } }
除了同步写入(但不是读取)之外,锁定或者说Monitor.Exit应该导致易失性写入 。 我们现在说我们有两个线程A和B,并且发生以下序列:
- A读取
MyProperty
的当前值。 - B将新值写入
MyProperty
。 - A再次读取
MyProperty
的当前值。
问:A现在可以保证看到新值吗? 或者我们的锁只是确保B及时写入主内存,而不是其他线程读取新值? 或者答案可能取决于我们是在运行.Net 2+还是“弱”的ECMA实施?
不,因为读取没有明确的内存屏障,所以不能“保证”看到新值。
您可以使用ReaderWriterLockSlim
来确保a)写入相互锁定,以及b)读取始终拾取新值。
private readonly ReaderWriterLockSlim _myFieldLock = new ReaderWriterLockSlim(); private long _myField; public long MyProperty { get { _myFieldLock.EnterReadLock(); try { return _myField; } finally { _myFieldLock.ExitReadLock(); } } set { _myFieldLock.EnterWriteLock(); try { _myField = value; } finally { _myFieldLock.ExitWriteLock(); } } }
如果您在getter中使用Interlocked.Read,则应始终读取新值。 有关内存防护的更多信息,请参阅C#中的线程