Reputation: 308
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
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
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
Reputation: 1062820
The +=
operator, when used with an int
prop or field, is doing multiple operations:
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