October 7, 2008

Interlocked.CompareExchange Usage

System.Threading.Interlocked.CompareExchange(ref location, newValue, comparand)
Compare the value in location with comparand, if they are equal set the value of location to newValue. In all cases return the initial value of location

To protect an area of code without blocking:
volatile int _usingResource = 0;
...
// Only allow one thread to enter but do not queue up other threads
// IF (_usingResource == 0) THEN set _usingResource = 1; ... 
if (System.Threading.Interlocked.CompareExchange(ref _usingResource, 1, 0) == 0)
{  
  try
  {
    DoSomething();
  }
  finally
  {
    // No longer in use, reset it.
    // NOTE: Interlocked.Exchange not needed here as this is a write of a literal value!
    _usingResource = 0; // or Interlocked.Exchange(ref _usingResource, 0);
  }
}
else
{
   // Do nothing as the resource is currently in use, however the tread is not blocked.
}
Is almost semantically the equivalent of:
static object Lock = new System.Object();
public int CompareExchange(ref int loc, int value, int comp)
{
    Monitor.Enter(Lock);
    int ret = loc;
    if (ret == comp)  
        loc = value;
    Monitor.Exit(Lock);
    return ret;
}
although it does NOT use Monitors internally and following threads are not blocked, they proceed from the end of the if block.
There is a good example of this being used in the Windows Service Class Example

No comments: