5

I have read plenty of discussions and examples of how to make a property threadsafe. There is one on the page for this threadsafe wrapper class

The example given is this:

internal class MyThreadSafeCass
{
    // *** Lock ***
    private object PropertyLock = new object();

    // *** Property ***
    private int m_Property = 0;

    // *** Thread-safe access to Property using locking ***
    internal int Property
    {
        get
        {
            lock (PropertyLock)
            {
                return m_Property;
            }
        }
        set
        {
            lock (PropertyLock)
            {
                m_Property = value;
            }
        }
    }
}

It is clear what's happening here, and what the locks are doing, but I'm struggling to see why it is required. Why is the following not threadsafe? What can go wrong?

internal class MyThreadSafeCass
{
    // *** Property ***
    private int m_Property = 0;

    // *** Thread-safe access to Property using locking ***
    internal int Property
    {
        get
        {
            return m_Property;
        }
        set
        {
            m_Property = value;
        }
    }
}
bornfromanegg
  • 2,826
  • 5
  • 24
  • 40
  • Two threads (or more) can't access to memory at the same time. With your second sample, if two threads access the variable at the same time an AccessViolationException will throw. With the "lock" (or using Monitor object) you force the second thread to wait the first thread finish his work. without violation. – Yanos Aug 01 '15 at 09:22
  • Have a read of this article: http://blog.coverity.com/2014/03/12/can-skip-lock-reading-integer/#.VbyOn63EpYQ – Enigmativity Aug 01 '15 at 09:27
  • 1
    No, an `AccessViolationException` will not be thrown if two threads try to access a memory location at the same time. – user12864 Aug 01 '15 at 14:54
  • @Enigmativity I can't decide if this is a case of computers being to clever for their own good, or just cleverer than me! Either way, I wouldn't dream of arguing with Mr. Lippert. I think that answers my question. If you posted that as an answer I'd accept it. Thanks. – bornfromanegg Aug 02 '15 at 19:42

2 Answers2

0

a expression like: m_Property++; in more than one thread parallel returns different values. Especially on multi core cpus.

  • The old value get loaded into the cache of the cpu.
  • The value will be incremented by the cpu
  • The new value will be saved back to the memory.

Example:

  • core one will load value as 10
  • core two will load value as 10 at the same time as core one
  • both add one (value is 11)
  • both will save data back to memory
  • the result will be 11.
  • but you expect 12

See this for further details

Klaus Fischer
  • 125
  • 1
  • 6
  • It doesn't answer the question, because this problem is not solved by any of the classes given. In both cases executing `obj.Property++` concurrently will lead to unexpected results. – Dzienny Aug 01 '15 at 10:41
  • And the lock will do exactly nothing to prevent the race condition outlined here. – Voo Aug 02 '15 at 19:25
0

@Enigmativity gets the kudos here (if not the points, unfortunately) by linking to this blog about skipping locks, which in turn links to this blog about CPU reordering optimizations, which is the real meat of the answer.

In summary, CPUs can (and do) apply optimisations to code which involve changing the order in which reads/writes are executed. These changes are guaranteed to be consistent and imperceptible within the thread in which they are executing. However, they do not (can not) guarantee consistency across multiple threads accessing shared memory. Locking, as displayed in the example in the initial question, imposes restrictions on accessing this shared memory which restore consistency.

As I say, this is a summary. I cannot add anything to the description in the blogs linked to above, so would defer anyone interested in knowing the full answer to follow those links.

@Enigmativity, I will still accept this as an answer from you if you post it as such. Otherwise, I'll accept this answer and close this off.

bornfromanegg
  • 2,826
  • 5
  • 24
  • 40