C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Tip: These change the operations to be atomic. This means no operations can be performed on the value during the call.
Next: This example familiarizes us with the syntax of Interlocked and Interlocked.Add.
Info: When running this program, there is no chance that thread 1 or thread 2 will read the value of the field before the other thread has written to it.
Warning: Without Interlocked, both threads could read the value, then both change it afterwards. The result would be 1 not 2.
Thread JoinThreadStartC# program that uses Interlocked.Add
using System;
using System.Threading;
class Program
{
static int _value;
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(A));
Thread thread2 = new Thread(new ThreadStart(A));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine(Program._value);
}
static void A()
{
// Add one.
Interlocked.Add(ref Program._value, 1);
}
}
Output
2
C# program that uses Interlocked.Increment and Decrement
using System;
using System.Threading;
class Program
{
static int _value;
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(A));
Thread thread2 = new Thread(new ThreadStart(A));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine(Program._value);
}
static void A()
{
// Add one then subtract two.
Interlocked.Increment(ref Program._value);
Interlocked.Decrement(ref Program._value);
Interlocked.Decrement(ref Program._value);
}
}
Output
-2
CompareExchange: This encodes both a conditional and an assignment. If the value equals the second argument, it is changed to the third argument.
C# program that uses Interlocked
using System;
using System.Threading;
class Program
{
static long _value1;
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(A));
thread1.Start();
thread1.Join();
// Written [2]
Console.WriteLine(Interlocked.Read(ref Program._value1));
}
static void A()
{
// Replace value with 10.
Interlocked.Exchange(ref Program._value1, 10);
// CompareExchange: if 10, change to 20.
long result = Interlocked.CompareExchange(ref Program._value1, 20, 10);
// Returns original value from CompareExchange [1]
Console.WriteLine(result);
}
}
Output
10
20
Here: The result is correct because the value printed is equal to the total number of increment operations.
Result: Interlocked.Increment was several times faster, requiring only 6 nanoseconds versus 40 nanoseconds for the lock construct.
C# program that tests Interlocked performance
using System;
using System.Diagnostics;
using System.Threading;
class Program
{
static object _locker = new object();
static int _test;
const int _max = 10000000;
static void Main()
{
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
lock (_locker)
{
_test++;
}
}
s1.Stop();
var s2 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
Interlocked.Increment(ref _test);
}
s2.Stop();
Console.WriteLine(_test);
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
Console.Read();
}
}
Output
20000000
40.02 ns
6.40 ns [Interlocked.Increment]