写一个锁是否保证在另一个线程中读取新内容? (.Net,内存模型)

时间:2011-03-06 05:35:46

标签: c# .net concurrency locking memory-model

假设我有一个属性,其setter受锁的保护,但没有锁定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的当前值。
  4. 问:现在A保证会看到新值吗?或者我们的锁只是确保B及时写入主内存,而不是其他线程读取新值?或者答案可能取决于我们是在运行.Net 2+还是“弱”的ECMA实施?

2 个答案:

答案 0 :(得分:3)

不,由于读取没有明确的内存屏障,因此无法“保证”看到新值。

您可以使用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();
        }
    }
}

答案 1 :(得分:1)

如果您在getter中使用Interlocked.Read,则应始终读取新值。有关内存栅栏的详细信息,请参阅Threading in C#