views:

69

answers:

6

Hello everyone. Up to this point I used lock(object) construction for acces to shared variables. After reading msdn article about Interlocked

The Increment and Decrement methods increment or decrement a variable and store the resulting value in a single operation. On most computers, incrementing a variable is not an atomic operation, requiring the following steps:

Load a value from an instance variable into a register.

Increment or decrement the value.

Store the value in the instance variable.

If you do not use Increment and Decrement, a thread can be preempted after executing the first two steps. Another thread can then execute all three steps. When the first thread resumes execution, it overwrites the value in the instance variable, and the effect of the increment or decrement performed by the second thread is lost.

I figure out that lock can fail my programm potentially:)

Are my decisions correct ?

p.s ssory for bad english(

+2  A: 

Interlocked semantics can be thought of as the ++ and -- operators wrapped inside a lock (for Interlocked.Increment and Interlocked.Decrement respectively).

The MSDN quote is talking about code not inside a lock block.

Oded
+1  A: 

No, if you lock appropriately you should be fine... because even if one thread is pre-empted in the middle of a compound operation, another thread won't be able to mess with the same variables, because it won't be able to acquire the same lock.

Of course, this is assuming you're locking on the same monitor for all pieces of code affecting the same variables.

Jon Skeet
+3  A: 

Successful use of any concurrency mechanism whether lock() or Interlocked, or others that .Net Framework offers depends on a) using the lightest-weight mechanism which meets your requirements, and b) correct implementation.

lock() is useful for ensuring that a block of code (what follows the lock()) cannot be executed by any other thread, and also excludes access to any other block of code that concurrently lock()s on the same target in a different thread.

Interlocked is useful for hardware-level atomic access to primitive types of a certain size - typically pointer (in native code), Int32 and Int64. This is great for performance, but limited in scope.

Neither is 'wrong', they just meet different usage patterns. In other circumstances (lots of readers and infrequent writers to a shared data structure) you might prefer a ReaderWriterLockSlim to either of Interlocked and lock().

It's worth pointing out that mixing Interlocked and lock() for guarding concurrent access to a single primitive value IS wrong, since lock() does not offer the same atomicity guarantees as Interlocked.

It's also worth noting that you can optimize performance by avoiding contention completely as far as possible - do not share data between threads, and there is no issue with picking the best mechanism to prevent concurrent access. Of course this is not always possible but if you design your thread tasks carefully you may be able to avoid the issue by halding your inter-thread communication via Task Parallel Library. Also check out System.Collections.Concurrent, which offers collections that you can safely access without your own locking.

Steve Townsend
"and also excludes access to any other block of code that lock()s on the same target" - That's not entirely true. If I call B from A and both A and B lock on C, B can execute as long as its on the same thread.
Jeff Yates
@Jeff - good point, I'l clarify this.
Steve Townsend
+1  A: 

The key to both lock() and Interlocked is being consistent. lock() synchronizes code based on the object provided. If you have a lock() around access to variable myVariable in one thread but code that accesses myVariable in another thread without a lock, then it's not safe. Likewise, if you use Interlocked in one place and don't in another, it's not safe.

Sam
+1  A: 

Interlocked class provide operations(Increment , Decrement Excahnage) which are thread safe even if you are on different core.

so rather than writing lock code , you can make use of this specilized class

saurabh
+1  A: 

Your code should be fine if you are using lock(object) correctly. Interlocked is simply another means to acheive thread synchronisation for certain operations.

using lock...

private int foo;
private object fooLock = new object();

public void Increment()
{
    lock (fooLock)
    {
        foo++;
    }
}

using Interlocked... (this should be much faster)

private int foo;

private void Increment()
{
    Interlocked.Increment(ref foo);
}
AdamRalph