-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
The methods on the Interlocked class currently only allow arithmetic operations (addition, subtraction) and exchange operations. These are sufficient for normal arithmetic needs but are somewhat difficult to use by callers who need to perform interlocked manipulation of fields that are intended to be bitwise flags.
As an example, consider ASP.NET's internal CancellationTokenHelper class, which uses several calls to Interlocked.CompareExchange within a switch statement in order to mimic performing flag manipulation of a field. (http://referencesource.microsoft.com/#System.Web/Util/CancellationTokenHelper.cs,71)
Or consider how System.Threading.Task uses Interlocked.CompareExchange in a loop to mimic the InterlockedAnd operation. (http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,865)
While it's possible for callers to implement interlocked bitwise operations in terms of interlocked arithmetic operations, it's a bit difficult to get right, and the framework should make this easier for the power developers who need it.
Proposed API additions
namespace System.Threading {
public static class Interlocked {
public static int And(ref int location1, int value);
public static long And(ref long location1, long value);
public static int Or(ref int location1, int value);
public static long Or(ref long location1, long value);
public static int Xor(ref int location1, int value);
public static long Xor(ref long location1, long value);
}
}Behavior
Like their arithmetic counterparts, these APIs perform the operation atomically and return the original value to the caller.
At the IL level, these APIs can be implemented in terms of the existing APIs on the Interlocked class. Ideally the JITter could special-case when the caller discards the return value without inspection, and this would turn in to a lock and or similar instruction instead of a standard lock cmpxchg.
The proposed APIs should have the same memory fence semantics that the arithmetic operations have today. (I believe it's a full fence?)
Samples
The System.Threading.Task code from earlier, as it exists today:
// Atomically clear the END_AWAIT_NOTIFICATION bit
SpinWait sw = new SpinWait();
while (true)
{
int oldFlags = m_stateFlags;
int newFlags = oldFlags & (~TASK_STATE_WAIT_COMPLETION_NOTIFICATION);
if (Interlocked.CompareExchange(ref m_stateFlags, newFlags, oldFlags) == oldFlags) break;
sw.SpinOnce();
}Could be written as such with the new primitives (n.b. caller doesn't care about return value, so JIT optimization described earlier could kick in):
// Atomically clear the END_AWAIT_NOTIFICATION bit
Interlocked.And(ref m_stateFlags, ~TASK_STATE_WAIT_COMPLETION_NOTIFICATION);