3

假设我有一个属性,其设置器受锁保护,但在 getter 周围没有任何锁,例如

private long _myField;
public long MyProperty
{
    get { return _myField; }
    set { lock(whatever) _myField = value; }
}

除了同步写入(但不是读取)之外,锁,或者更确切地说 Monitor.Exit,应该会导致volatile write。现在假设我们有两个线程 A 和 B,并且发生以下序列:

  1. A 读取 的当前值MyProperty
  2. B 将新值写入MyProperty
  3. A 再次读取 的当前值MyProperty

问:A 现在可以保证看到新值吗?还是我们的锁只是确保 B 及时写入主内存,而不是确保其他线程读取新值?或者答案甚至取决于我们是在 .Net 2+ 还是“较弱”的 ECMA 实现中运行?

4

2 回答 2

3

不,由于读取没有显式的内存屏障,因此不能“保证”看到新值。

您可以使用 aReaderWriterLockSlim来确保 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();
        }
    }
}
于 2011-03-06T05:45:22.047 回答
1

如果您在 getter 中使用了 Interlocked.Read,您应该始终读取新值。有关内存栅栏的更多信息,请参阅C# 中的线程

于 2011-03-06T05:55:09.340 回答