Does a lock around a write guarantee fresh read in

2019-04-01 06:48发布

问题:

Say I have a property whose setter is protected by a lock, but without any lock around the getter, e.g.

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

In addition to synchronizing writes (but not reads), the lock, or rather Monitor.Exit, should cause a volatile write. Let's now say we have two threads A and B, and the following sequence happens:

  1. A reads the current value of MyProperty.
  2. B writes a new value to MyProperty.
  3. A reads the current value of MyProperty again.

Q: Is A now guaranteed to see the new value? Or did our lock just ensure that B writes to main memory in a timely manner, but not that other threads read a fresh value? Or could the answer even depend on whether we're running in .Net 2+ or a "weaker" ECMA implementation?

回答1:

No, since the read does not have the explicit memory barrier, it is not "guaranteed" to see the new value.

You can use a ReaderWriterLockSlim to insure that a) the writes lock each other and b) the reads always pickup the new value.

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();
        }
    }
}


回答2:

If you used Interlocked.Read in the getter you should always read the new value. See Threading in C# for more information about memory fences