Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / threads

Thread Synchronization with Interlocked Class

4.83/5 (4 votes)
28 Nov 2011CPOL5 min read 46.7K   868  
An introduction to interlocked class for thread synchronization in .NET Framework
image001.jpg

Introduction

This article describes the thread synchronization technique with interlock class present in .NET Framework. Interlock class provides atomic operation on shared variable. The operating system will not interrupt their operation at the middle of its execution.

Interlock class provides a different thread safe method for different operations with limited data type support. This class is used when we need to increment, decrement, exchange, etc. on shared variable between multiple threads.

Issue without Synchronization

Consider the following line of code which increments the shared variable X inside the multi threading environment.

C#
int X=0;
X=X+1;

From the programming point of view, the line X=X+1 is an atomic operation. But internally to execute this line, the computer needs to do more. We can break the above line in three operations:

  • Move the value of X to CPU register.
  • Increment the value in register.
  • Save the value back to memory.

Suppose there are 2 threads executing the same line of code. Imagine the first thread is in step 2 means the value if X has incremented to 1. At this point of time, the operating system stops the first thread. The second is also running in parallel. The second thread finishes all three steps and updates the value of X to 1. Now assume the first thread is resuming its operation and executes the third step. At this step, the value of X is updated from 0 to 1 which is the old value get updated. This means that after executing the above line of code, the value of X would be 1 which is incorrect. The value of X should be 2.

Resolution

By using interlocked class, we can solve this issue and can get the expected value which is 2. Interlocked class provides a simple thread safe method Interlocked. Increment (ref variable) for increment operation. It ensures that the operating system will not interrupt the Increment Operation.

Using the Code

It’s very common for every developer to Increment, Decrement and Exchange operation on shared variable in multithreaded environment. Without synchronization, we may not get the result as expected. But with thread synchronization, we can get the expected result. In the following section, I have described the actual implementation in both scenarios.

Shared variable Increment without Synchronization

The following code increments the shared variable by multiple threads without any synchronization.

C#
int Number = 0;
private void btnWithSync_Click(object sender, EventArgs e)
{
            int TotalThread = 10000;
            Thread[] IntreLockThread = new Thread[TotalThread];
            for (int i = 0; i < TotalThread; i++)
            {
                IntreLockThread[i] = new Thread(new ThreadStart(UpdateValue));
                IntreLockThread[i].IsBackground = true;
                IntreLockThread[i].Priority = ThreadPriority.Lowest;
                IntreLockThread[i].Start();
            }
            for (int i = 0; i < TotalThread; i++)
            {
                //Block main thread until all child thread to finish.
                IntreLockThread[i].Join();
            }
            //Show the current value of Number after incremented by all thread
            lblTotalValue.Text = Number.ToString();
}
 
///Description : Increment the Number variable and Update Listboxwith current value.
public void UpdateValue()
{
           listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateListBox1), 
		"Thread ID : " +
           Thread.CurrentThread.ManagedThreadId + " - B:: =" + Number.ToString());
           Number++; // Increment without synchronization
           listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateListBox1), 
		"Thread ID : " +
           Thread.CurrentThread.ManagedThreadId + " - A:: =" + Number.ToString());
}
public void UpdateListBox1(object objResult)
{
            listBox1.Items.Add(objResult.ToString());
}

In the above code, I have run 10000 threads in a row to increment the shared variable. But at the end, all thread execution is complete; the value of the variable should be 10000. But partially it’s not happening. Sometimes, the value is less than 10000 (in my last run, the value was 9995). This happens due to context switching between threads. Operating system can interrupt the current executing thread and stop execution at the middle of increment and later on, it resumes the operation. This will replace the value of variable with old value. So the increment operation in this way is not atomic. We can use interlocked class to resolve this issue.

Shared Variable Increment with Synchronization

The following code increments the shared variable by multiple threads with the help of interlocked class. The Increment method of interlocked class is used for this purpose.

C#
int Number = 0;
private void brnWithSync_Click(object sender, EventArgs e)
{
            Number = 0;
            int TotalThread = 10000;
            Thread[] IntreLockThread = new Thread[TotalThread];
            for (int i = 0; i < TotalThread; i++)
            {
                IntreLockThread[i] = new Thread(new ThreadStart(UpdateWithInterlock));
                IntreLockThread[i].IsBackground = true;
                IntreLockThread[i].Start();
            }
            for (int i = 0; i < TotalThread; i++)
            {
                //Block main thread until all child thread to finish.
                IntreLockThread[i].Join();
            }
            //Show the current value of Number after incremented by all thread
            lblTotalValueSync.Text = Number.ToString();
}
 
///Description : Increment the Number variable and Update Listboxwith current value.
public void UpdateWithInterlock()
{
            listBox2.BeginInvoke(new ParameterizedThreadStart(UpdateListBox2), 
		"Thread ID : " +
            Thread.CurrentThread.ManagedThreadId + " - B:: =" + Number.ToString());
            Interlocked.Increment(ref Number); //Increment with interlock class.
            listBox2.BeginInvoke(new ParameterizedThreadStart(UpdateListBox2), 
		"Thread ID : " +
            Thread.CurrentThread.ManagedThreadId + " - A:: =" + Number.ToString());
}
 
//Show the current value of Number after incremented by all thread
public void UpdateListBox2(object objResult)
{
            listBox2.Items.Add(objResult.ToString());
}

As previous, I have run 10000 threads in a row to increment the shared variable. At the end of execution, I got the expected result. The value of the variable is incremented to 10000. So the increment operation in this way is atomic and it’s fully synchronized.

Interlocked class supports more operations along with Increment. All methods of this class take the first parameter as reference type so that we can get the updated value after the operation completes. All non generic methods of this class have overloaded versions that exist. Here I have described only one version.

Following are the different thread safe methods of interlocked class:

C#
Interlocked.Add(ref int intNumber,int value);

This method adds the value of two parameters and replaces the first one with the sum of both values as an atomic operation.

C#
Interlocked.Increment(ref int intNumber);

This method increments the value by 1 and assigns the updated value to itself as an atomic operation.

C#
Interlocked.Decrement(ref int intNumber);

This method decrement the value by 1 and assigns the updated value to itself as an atomic operation.

C#
Interlocked.Read(ref int intNumber);

It returns the value of variable specified in parameter.

C#
Interlocked.Exchange(ref intNumber1, int intNumber2);

The exchange method assigns the value of first parameter with the value of second parameter as an atomic operation. It’s basically a set operation. Someone can think why we should use this function as the new value doesn’t depend on the old one. But it's necessary multi-processor or multi-core machine environment.

C#
Interlocked.Exchange<T>(ref T Location, T value)

This method is a generic version of exchange method. The functionality is the same as Exchange method. Here it must be reference type.

C#
Interlocked.CompareExchange(ref int intNumber1,int intNumber2,int CompareValue);

CompareExchange is a conditional assignment method. The first parameter is compared with the last parameter. If both are equal, then the value of the first parameter is replaced by the second parameter.

C#
Interlocked.CompareExchange<T>(ref T Location, T Value, T CompareValue);

This method is a generic version of CompareExchange method. The functionality is the same as Exchange method. Here T must be reference type.

Testing the Code

To test the above code, run the application. When running the code without synchronization by clicking on “Run without Synchronization” button, please try to keep the CPU busy by opening a new different application so that context switch happens. To run the code with synchronization using interlocked class, click on “Run with Synchronization” and get the actual result as the expected result.

Conclusion

I have quite enjoyed writing this article. I think this article gives the basic overview of interlock class, a thread synchronization technique provided in .NET Framework.

History

  • 20th November, 2011: Initial version
  • 22nd November, 2011: Article updated

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)