Modifying a shared integer in a thread-safe manner in .NET

The Interlocked class in the System.Threading namespace provides a number of useful methods to modify the value of an integer that is shared among multiple threads.

Consider the following code. It updates the same shared integer in a loop on 5 different threads and prints the final status at the end. 3 threads add 1 to the integer 600 times and 2 threads subtracts 1 600 times. Therefore we’re expecting the shared integer to be 600 at the end:

public class InterlockedSampleService
{
	private int _sharedInteger;

	public void RunInterlockedSampleCode()
	{
		Task modifyTaskOne = Task.Run(() => ModifySharedIntegerInLoop(600, 1));
		Task modifyTaskTwo = Task.Run(() => ModifySharedIntegerInLoop(600, -1));
		Task modifyTaskThree = Task.Run(() => ModifySharedIntegerInLoop(600, 1));
		Task modifyTaskFour = Task.Run(() => ModifySharedIntegerInLoop(600, -1));
		Task modifyTaskFive = Task.Run(() => ModifySharedIntegerInLoop(600, 1));
		Task.WaitAll(modifyTaskOne, modifyTaskTwo, modifyTaskThree, modifyTaskFour, modifyTaskFive);
		Debug.WriteLine(string.Format("Final value: {0}", _sharedInteger));
	}

	private void ModifySharedIntegerInLoop(int maxLoops, int amount)
	{
		for (int i = 0; i < maxLoops; i++)
		{
			ModifySharedIntegerSingleTime(amount);
		}
	}

	private void ModifySharedIntegerSingleTime(int amount)
	{
		_sharedInteger += amount;
	}
}

If you repeatedly run the RunInterlockedSampleCode method then you may get 600 most of the times. However, if you execute it say 5-10 times you should eventually see at least 1 incorrect result. I ran it 10 times and got the following incorrect results:

297
589
632
379

So it failed 4 times out of 10. You’ll certainly get different results.

The point of this exercise is that if multiple threads are allowed to modify the same shared integer then you can never be sure what the state of that integer is at the time a certain thread modifies it.

There are a couple of ways to solve it but let’s concentrate on the Interlocked class. It has a number of methods that modify integers and longs in an atomic way, i.e. in a single transaction where only one thread is allowed access to a resource.

We only need change the code a little bit:

private void ModifySharedIntegerSingleTime(int amount)
{
	Interlocked.Add(ref _sharedInteger, amount);
}

Now you can execute the code as often as you want, you’ll get 600 every time.

Interlocked has the following interesting methods too:

  • Decrement: decrement the value of a number by one
  • Increment: increment the value of a number by one
  • Read: read the current value if a shared numeric field by one

View the list of posts on the Task Parallel Library here.

Advertisement

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

%d bloggers like this: