Introduction
In this article I am going to describe Non-Blocking Synchronization Constructs. There ae two Non-Blocking Synchronization Constructs:
Note : For a description of volatile, please read my article "Volatile keyword in C# Threading"; see http://www.c-sharpcorner.com/UploadFile/1d42da/volatile-keyword-in-C-Sharp-threading/
Interlocked class
Namespace : System.Threading
Assembly : mscorlib (in mscorlib.dll)
Remarks
The methods of this class help protect against errors that can occur when the scheduler switches contexts while a thread is updating a variable that can be accessed by other threads, or when two threads are executing concurrently on separate processors. The members of this class do not throw exceptions.
The Interlocked class belongs to the System.Threading namespace. When two threads try to update same variables or when two threads are concurrently executing there are chances of many error occurrences and incorrect data updates.
In those situations, the Interlocked class and its methods are very helpful to manipulate variables accessible by one or more threads without throwing any error or exception. Methods provided by the Interlocked class are listed below.
- Increment : Used to increment a variable's value and store its result. Int32 and Int64 integers are its legal parameters.
- Decrement : Used to decrement a variable's value and store its result. Int32 and Int64 integers are its legal parameters.
- Exchange : Used to exchange values between variables. This method has seven overloaded versions based on the different types it can accept as its parameter.
- CompareExchange : Compares two variables and stores the result of comparison in another variable. This method also has seven overloaded versions.
- Add : Adds two integer variables and updates the result in the first integer variable. It is used to add integers of type Int32 as well as Int64.
- Read : Reads an integer variable. It is used to read an integer of type Int64.
We know that variables that increment and decrement have their own framework class, the Interlocked
class. This class provides simple thread-safe methods to do some common tasks with variables. The Increment
and Decrement
methods add or subtract 1 from a variable. These methods can be considered "atomic". This means that the operating system will consider the entire operation as one not allowing other threads to interrupt their execution.
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.
Take a look at the following which ensures that the computer will not interrupt the incrementing or decrementing of the variable a:
int a=1;
a = Interlocked.Increment;
a = Interlocked.Decrement;
There are two additional methods in the Interlocked
class, Exchange
and CompareExchange
. Let's take a closer look at these two.
The Exchange method atomically exchanges the values of the specified variables. The second value could be a hard coded value or a variable. Don't let the name of the method, Exchange
, confuse you though. Only the first variable ed in the first parameter will be replaced by the second. The method won't really exchange the values of two.
int a = 2;
int b = 4;
Interlocked.Exchange(a, b); // now a equals to 4 and b still 4
Interlocked.Exchange(a,8); // now value of a is become 8
The CompareExchange method combines two operations: comparing two values and storing a third value in one of the variables, based on the outcome of the comparison. If both are equal then replace the one used as the first parameter with the supplied value.
int a=10 ;
Interlocked.CompareExchange(ref a,DateTime.Now.Day,10);
The above code creates a new integer and then assigns the value 10 to it. We then call the
Interlocked.CompareExchange method to compare the variable a
with 10 and since they are the same, it will replace a
with DateTime. Now. Day
, the current day of the month.
The following code example shows a thread-safe way to increment and decrement an integer value. SafeInstanceCount will always be zero. However, UnsafeInstanceCount will not necessarily be zero because a race condition occurs between incrementing and decrementing the count. This effect is especially marked on a multiprocessor computer.
using System;
using System.Threading;
namespace InterlockedClass
{
class akshay
{
static void ThreadMethod()
{
for (int i = 0; i < 10; i++)
{
new CountClass();
}
}
class CountClass
{
static int unsafeInstanceCount = 0;
static int safeInstanceCount = 0;
static public int UnsafeInstanceCount
{
get { return unsafeInstanceCount; }
}
static public int SafeInstanceCount
{
get { return safeInstanceCount; }
}
public CountClass()
{
unsafeInstanceCount++;
Interlocked.Increment(ref safeInstanceCount);
}
~CountClass()
{
unsafeInstanceCount--;
Interlocked.Decrement(ref safeInstanceCount);
}
}
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(ThreadMethod));
Thread thread2 = new Thread(new ThreadStart(ThreadMethod));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(CountClass.UnsafeInstanceCount);
Console.WriteLine(CountClass.SafeInstanceCount);
Console.Read();
}
}
}
Output
The Interlocked
class allows you to do basic programming techniques and make them thread safe.