Class System.Threading.Interlocked
Namespace: System.Threading
Provides methods that support an atomic, hardware-based thread-safe operation that accesses a variable passed by reference.
Summary
The Interlocked class provides several static methods that perform simple atomic operations on variables. These operations are thread-safe and are typically implemented using hardware instructions, making them very efficient. They are crucial for implementing lock-free data structures and for managing shared resources in multithreaded applications without the overhead of traditional locking mechanisms like mutexes or semaphores.
Common operations include incrementing, decrementing, adding, exchanging values, and comparing and swapping values. These methods ensure that no other thread can interfere with the operation while it is being performed.
Remarks
When dealing with concurrent programming, ensuring that operations on shared data are thread-safe is paramount. While locks (like Monitor or Mutex) provide a straightforward way to protect shared resources, they can introduce performance bottlenecks due to context switching and potential deadlocks. The Interlocked class offers a lower-level, more performant alternative for specific atomic operations.
For example, instead of using a lock to increment a counter, you can use Interlocked.Increment(). This single operation is guaranteed to be atomic, meaning it completes entirely without interruption from other threads. Similarly, Interlocked.CompareExchange() is fundamental for implementing lock-free algorithms, allowing threads to attempt to update a value only if it hasn't been changed by another thread since it was last read.
It is important to note that Interlocked operations are only atomic for the specific operations they provide. If you need to perform a sequence of operations that must be treated as a single, indivisible unit, you will still need to use traditional locking mechanisms.
Methods
| Name | Description |
|---|---|
| CompareExchange | Atomically compares two variables for equality and, if they are equal, replaces the second variable with a third variable and returns the original value of the second variable. |
| Decrement | Atomically decrements the specified variable by 1. |
| Exchange | Atomically sets the specified variable to the specified new value and returns the original value of the variable. |
| Increment | Atomically increments the specified variable by 1. |
| Add | Atomically adds two 32-bit integers and returns the sum. |
| Read | Atomically reads the value of the specified variable. |
Method CompareExchange<T>(ref T location1, T value, T comparand)
Atomically compares two variables for equality and, if they are equal, replaces the second variable with a third variable and returns the original value of the second variable.
Summary
This is the cornerstone of many lock-free algorithms. It checks if the current value of location1 is equal to comparand. If it is, the value of value is placed into location1. The original value of location1 is returned, regardless of whether the exchange occurred.
Remarks
Use this method when you need to update a shared variable only if its current value matches an expected value. This prevents race conditions where another thread might modify the variable between your read and write operations.
Parameters
ref T location1: A reference to the variable with which the comparison is made and, if equal, replaced.T value: The new value to set the variable to if the comparison is equal.T comparand: The variable with which to compare the contents oflocation1.
Returns
The original value of location1.
Example
// Example using CompareExchange to update a reference atomically
object lockToken = new object();
object oldValue = null;
object newValue = new object();
// Attempt to swap 'oldValue' with 'newValue' if 'oldValue' is null
oldValue = Interlocked.CompareExchange(ref lockToken, newValue, null);
if (oldValue == null)
{
Console.WriteLine("Successfully acquired the lock.");
}
else
{
Console.WriteLine("Lock was already held.");
}
Method Decrement(ref int location)
Atomically decrements the specified variable by 1.
Summary
Decrements the integer variable referred to by location by one. This operation is guaranteed to be thread-safe.
Parameters
ref int location: A reference to the 32-bit integer to be decremented.
Returns
The decremented value.
Example
// Example using Interlocked.Decrement
int counter = 10;
int newValue = Interlocked.Decrement(ref counter);
Console.WriteLine($"Counter is now: {counter}, returned value: {newValue}"); // Output: Counter is now: 9, returned value: 9
Method Exchange<T>(ref T location1, T value)
Atomically sets the specified variable to the specified new value and returns the original value of the variable.
Summary
Replaces the value at location1 with value and returns the value that was at location1 before the replacement. This operation is atomic.
Parameters
ref T location1: A reference to the variable to be replaced.T value: The new value to set the variable to.
Returns
The original value of location1.
Example
// Example using Interlocked.Exchange
string oldName = "Alice";
string newName = "Bob";
string originalName = Interlocked.Exchange(ref oldName, newName);
Console.WriteLine($"Original name: {originalName}"); // Output: Original name: Alice
Console.WriteLine($"Current name: {oldName}"); // Output: Current name: Bob
Method Increment(ref int location)
Atomically increments the specified variable by 1.
Summary
Increments the integer variable referred to by location by one. This operation is guaranteed to be thread-safe.
Parameters
ref int location: A reference to the 32-bit integer to be incremented.
Returns
The incremented value.
Example
// Example using Interlocked.Increment
int counter = 5;
int newValue = Interlocked.Increment(ref counter);
Console.WriteLine($"Counter is now: {counter}, returned value: {newValue}"); // Output: Counter is now: 6, returned value: 6
Method Add(ref int location, int value)
Atomically adds two 32-bit integers and returns the sum.
Summary
Adds the specified value to the integer variable referred to by location. The result is stored back in location, and the final sum is returned. This operation is atomic.
Parameters
ref int location: A reference to the 32-bit integer to which the value will be added.int value: The 32-bit integer to add tolocation.
Returns
The sum of the original value of location and value.
Example
// Example using Interlocked.Add
int balance = 100;
int deposit = 50;
int newBalance = Interlocked.Add(ref balance, deposit);
Console.WriteLine($"Current balance: {balance}"); // Output: Current balance: 150
Console.WriteLine($"New balance returned: {newBalance}"); // Output: New balance returned: 150
Method Read(ref long location)
Atomically reads the value of the specified 64-bit variable.
Summary
Reads a 64-bit integer in an atomic operation. This is important on architectures where a read of a 64-bit value might not be atomic.
Parameters
ref long location: A reference to the 64-bit integer to read.
Returns
The value read from the specified variable.
Example
// Example using Interlocked.Read
long largeCounter = 10000000000L;
long currentValue = Interlocked.Read(ref largeCounter);
Console.WriteLine($"The current value is: {currentValue}"); // Output: The current value is: 10000000000