Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

interlocked - when do I use it?

Tags:

c#

I just found out about the Interlocked class and now I have some basic questions.

From my understanding I should use Interlocked when manipulating numeric variables when multi-threading. If that statement is true, what about doing reads or just general using of the variables?

For example:

if ((iCount % 100) == 0)

Do I need to use an Interlocked statement there?

What about when I'm initializing the variable:

Int32 iCount = 0;

I need to make sure I understand this before implmenting it.

like image 927
webdad3 Avatar asked May 07 '13 13:05

webdad3


2 Answers

There are various factors here, but principally volatility and atomicity. In your statement:

if ((iCount % 100) == 0)

Do I need to use an Interlocked statement there?

we first need to ask "what is iCount?". If it is long / ulong, then it is not guaranteed to be atomic, so you absolutely need some kind of protection (such as via Interlocked) to avoid getting a "torn" value (reading it half-way through being updated, giving a phantom value that it never actually was - for example, changing from 00000000 to FFFFFFFF you could read 0000FFFF or FFFF0000). If it is an int, it will be guaranteed atomic. The next question is: do I need to see updates? The CPU has various levels of caching built in, and code that appears to read from a field can end up actually just reading from a local register or cache - and never touching the actual memory. If that is a risk, then you can mitigate that by using Interlocked, although in many cases using volatile will also guard against this.

The third and tricker question comes when discussing updates: do you want "last edit blindly wins"? if so, just update the value (presumably using volatile to allow reads) - however - there is a risk of lost updates if two threads are editing. As an example, if two threads each increment and decrement at the same time the final value could be 0 or 1 - not necessarily what you wanted. Intelocked offers ways to do updates with change-detection, and helper methods to do common operations like increment / decrement / add / etc.

Re your other question:

What about when I'm initializing the variable:

Int32 iCount = 0;

Field-initializers are only executed on one thread, so do not need additional protection - that is fine.


However! Threading is hard. If you are at all unsure, keep it simple: use lock. For example (assuming you want per-instance synchronisation):

private int iCount = 0;
private readonly object syncLock = new object();
...
lock(syncLock) {
    // code that reads or manipulates iCount
}

In many cases, this works fine.

like image 105
Marc Gravell Avatar answered Sep 28 '22 14:09

Marc Gravell


When doing multithreading over shared, mutable state you need to synchronize. You do not need to use Interlocked. Interlocked is for advanced users. I suggest you use the lock C# statement and only use Interlocked for easy cases (increment a shared counter) or performance critical cases.

Interlocked can only be used to access a single variable at a time and only quite primitive operations are supported. You will have a really hard time synchronizing multiple variables with Interlocked.

In your example, nobody can tell whether you need to synchronize or not because thread safety is a property of the whole program, not of a single statement or function. You need to regard all code operating on the shared state as a whole.

like image 41
usr Avatar answered Sep 28 '22 14:09

usr