Skip code if blocked?

It it possible to detect when Monitor.Enter is blocking, so i can skip the method.

As far as i understand, if an interrupt is triggered 3 times, then the interrupt routine will be triggered 3 times even if it has to wait. What if i want to avoid the interrupt routine if its blocked? Hope this makes sense?

You can use Interlocked.CompareExchange and similar functions to atomically test-and-set variables to get the effect of a conditional lock or semaphore. Exactly how you apply CompareExchange will depend on the locking semantics you want.

For instance, you could use CompareExchange to let the first interrupt through and make all others bypass the interrupt handling code if an interrupt is currently being serviced on another thread. This code would be added within your interrupt handler and would just return if the CompareExchange failed to do its exchange.

At least in full .NET Monitor has a TryEnter method.

but you can use a bool flag in combination with an lock to do so

private bool _isExecuting = false;
private readonly object _executionLock = new Object();
private void InterruptRoutine(...)
{
  if(_isExecuting)
    return;
  lock(_executionLock)
  {
    if(_isExecuting)
      return;
    try
    {
      _isExecuting  = true;

      // your code goes here
    }
    finally
    {
      _isExecuting  = false;
    }
  }
}

But if your interrupt handler is the NETMF managed one, then I think it will not be called twice at the same time, since NETMF only utalizes a single thread for these events.

…a good point - the strategies here only come into play if you are spinning a thread up for each interrupt.

Reinhard’s solution is equivalent to what I suggested - it just uses two checks of the flag instead of the atomic ‘Interlocked’ operators.

Could you post some sample code with the Interlocked operator?
Would be nice to lean something new :smiley:

Something like this:

private int _barrier = 0;
public void NonBlockingBarrier()
{
    // CompareExchange returns the value before the exchange, so
    //   if it was 0, then we are the winner. If not, we arrived late to
    //   the party, the value was already 1, and should return
    if (Interlocked.CompareExchange(ref _barrier, 1, 0) != 0)
        return;
    try
    {
        DoWorkSon();
    }
    finally
    {
        Interlocked.CompareExchange(ref _barrier, 0, 1);
    }
}

You can use Interlocked.Increment/Decrement to, say, let three threads in, but not more than three. I have used this pattern to create consumer threads that run until a queue is drained and then exit, which can reduce the total number of threads created, reduce heap churn and context switching.

6 Likes

@ mcalsyn - That’s some nice feature I didn’t know.
Guess I have to find my “I’ve learned something today” shirt again :dance:

1 Like

these technique look very useful…thanks guys