Is there anyway of replacing this code using the Interlocked.Exchange
API?
if (IsWorking == false)
{
lock (this)
{
if (IsWorking == false)
{
IsWorking = true;
}
}
}
Yes, but whether it would be useful is another matter.
You could replace isWorking
with an integer, and then use Interlocked.CompareExchange(ref isWorking, 1, 0)
.
This is pointless though; either way the result at the end is that isWorking
is 1
, so we would have better concurrency by just replacing the code with IsWorking = true
(or perhaps a VolatileWrite
to ensure it was seen by other CPUs).
Your code is probably a reduction of something like:
if (isWorking == false)
lock (this)
if (isWorking == false)
{
DoSomethingWorthDoing();
isWorking = true;
}
And it's the DoSomethingWorthDoing()
part that falls down.
There are ways of improving the concurrency of such double-checked locks, but it depends on a few things. One example is:
if(someUsefulThing == null)
Interlocked.CompareExchange(ref someUsefulThing, SomeUsefulFactory(), null);
At the end of this someUsefulThing
will be set to the result of SomeUsefulFactory()
, and after being set it will not be set again. There will though be a period in which we might call SomeUsefulFactory()
multiple times just to throw the result away. Sometimes that's a disaster, sometimes that's fine, and sometimes we could have just done no locking and been fine; it depends on just why we're concerned to share the same object here.
There are further variants, but applicability depends on just why you care about concurrency. This code, for example, implements a thread-safe concurrent dictionary using such interlocked operations, which tends to be slower than just putting a lock
around accessing a dictionary when contention is low, but much better when many threads access it at the same time.