Is AutoResetEvent the right choice for an atomic switch?

Suppose I process a large amount of input from multiple threads. I might want this data to act as a trigger for a specific action when certain criteria are met. However, the action is not repeated; therefore, the same trigger, fired twice in quick succession, should trigger only one action.

Using a simple bool flag to indicate whether an action is currently valid is not a reliable solution, as a race condition may arise, and two (or more) threads can still continue the same action at the same time. Of course, A bool in the lock statement of a synchronization object will work; but I generally prefer to avoid locking whenever possible *.

I am currently doing AutoResetEvent in these cases as essentially a form of atomic switch. The code usually looks something like this:

 if (conditionMet && readyForAction.WaitOne(0)) { try { doAction(); } finally { readyForAction.Set(); } } 

This works, but it seems to me that this may be more than an ideal use case for the AutoResetEvent class. Could you say that this is a suitable solution to this problem or does it make sense to use some other mechanism?


Update : as John pointed out , using Monitor.TryEnter as a locking strategy (instead of a simple lock , which I am roughly equivalent to Monitor.Enter ) is really quite simple:

 if (conditionMet && Monitor.TryEnter(lockObject)) { try { doAction(); } finally { Monitor.Exit(lockObject); } } 

However, I am very inclined to go with Henk's idea of using Interlocked . It seems as simple as possible.

+4
source share
2 answers

A simple (and fast) System.Threading.Interlocked.CompareExchange() will do.

 //untested int flag = 0; if (conditionMet && Interlocked.CompareExchange(ref flag, 1, 0) == 0) { try { doAction(); } finally { flag = 0; // no need for locking } } 
+3
source

"I generally prefer to avoid blocking when possible" - why? It sounds like you're effectively doing something very similar here, but using Windows synchronization primitives instead of the CLR. You are trying to synchronize, so that only one thread can run a specific piece of code at a time ... it certainly sounds like a lock to me. The only difference is that if the lock is already saved, you don’t want to execute the code at all.

You should be able to achieve the same effect using Monitor.TryEnter , which I personally argue about, a little easier to understand. (Again, I "grew up" with Java monitors, so it is closer to my background.)

+2
source

All Articles