3

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?

ehnmark
  • 2,656
  • 3
  • 24
  • 20

2 Answers2

3

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();
        }
    }
}
The Scrum Meister
  • 29,681
  • 8
  • 66
  • 64
1

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

BrandonAGr
  • 5,827
  • 5
  • 47
  • 72