Dan Le
Dan Le

Reputation: 308

Memory assignment in C# for operator + or ++

Please forgive me if the question is asked before, as I cannot find a good keyword to search for it. So if you have any recommendation for the keyword for the problem below, please let me know.

So the question is: suppose I have a class

class Test
{
   public int testProp;
}

When I do something like

var testInstance = new Test();
testInstance.testProp += 10;

will the address of the testProp still be the same as it is before the + operation? When I tried with the Visual Studio disassembly window, I see that it seems to copy the new value to the same address (Please correct me here as I'm in no where familiar with Assembly lang).

I'm asking because in case of multiple thread access the property and increase its value concurrently

var list = new List<Task>();
for (var z = 0; z < 2000; z++)
{
   list.Add(Task.Run(() =>
      {
         testInstance.testProp+=10;
      }));
}

sometimes it would give me 20000, but sometimes only 19990 or less, so I'm quite confused if the address of testProp is changed, and if not how is the value of the address is read that makes the sum less than 20000 in this case?

Upvotes: 1

Views: 67

Answers (3)

Geoduck
Geoduck

Reputation: 9003

The memory address doesn't change. However, the += operator is not atomic. This means, it will not read the value, increment it and replace the original value in a single operation. Imagine the sequence of incrementing as this:

READ value
INC value
WRITE value

With multiple threads, these can be mixed up:

THREAD A READ value
THREAD B READ value  # same value read
THREAD B INC value
THREAD B WRITE value
THREAD A INC value
THREAD A WRITE value   # does not take into account value written by B

So, when you think it should have been incremented twice, in fact it was only incremented once. As all the work done in Thread B is overwritten by thread A.

Upvotes: 3

Krumelur
Krumelur

Reputation: 32497

The sync between multiple threads has nothing to do with which memory address it writes to. To perform multi threading safe atomic operations use the Interlocked class, i.e. Interlocked.Increment.

Upvotes: 2

Marc Gravell
Marc Gravell

Reputation: 1062820

The += operator, when used with an int prop or field, is doing multiple operations:

  • get
  • add
  • set

This means that it is not atomic, and race conditions can cause lost changes. If you want an atomic increment, you can use:

Interlocked.Add(ref testInstance.testProp, 10);

This has more overhead, but it will give you the correct result. If you don't have direct access to the field, you would have to synchronize, probably via lock.

Upvotes: 1

Related Questions