14

I have a part of code in an Async/Await function that I only want one thread to execute at a time.

This is relatively simple by creating a new SemaphoreSlim(1) and using WaitAsync/Release. The effect is that the first thread executes while the others wait and then execute one by one.

What I am trying to achieve is actually slightly different. I would like the other threads not to wait, but to return out of the function (i.e. I don't want to block the other threads). So if there was a property "NumberOfThreadsCurrentlyExecuting" I would effectively have an If Semaphore.NumberOfThreadsCurrentlyExecuting > 0 Then Return.

But such a property doesn't exist. Does anyone have any idea for a way around this problem?

Thanks Charles

Charles
  • 463
  • 2
  • 6
  • 15
  • 1
    Check [CurrentCount](http://msdn.microsoft.com/en-us/library/system.threading.semaphoreslim.currentcount.aspx)? – Blorgbeard Aug 13 '14 at 22:09
  • Right. Stupid question. Sorry! I understood CurrentCount was refering to the maximum number of threads not the remaining. – Charles Aug 13 '14 at 22:14
  • and realising where my mistake comes from: the tooltip in VS for CurrentCount says "Gets the number of threads that will be allowed to enter the System.Threading.SemaphoreSlim", which is ambiguous (and I interpreted as maximum). – Charles Aug 13 '14 at 22:26

2 Answers2

36

How about using the SemaphoreSlim.Wait/Async with a zero-timeout? If it can't enter the semaphore (because it's already been entered), it will return false.

Note that Monitor (and thus lock) is completely unsuited to async

(hence the fact that you can't await in a lock) because

  1. your task may continue on another thread after you've entered the lock (thus you will try to release the lock from another thread)
  2. after you've awaited, another continuation may use your thread (while it is still holding the lock), so if it attempts to acquire the lock it will succeed
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Mark Sowul
  • 10,244
  • 1
  • 45
  • 51
-3

Instead of a Semaphore, you could just use a Monitor.

If you call TryEnter and it fails, another thread is in the "lock".

This is thread safe (unlike checking semaphore counts), and fairly simple:

// using somethign like: object sync = new object();

bool lockTaken = Monitor.TryEnter(sync);
try
{
  if (lockTaken) 
  {
      // You're here - do your work
  }
  else
  {
      // Something else was in the thread - exit?
      return;
  }
}
finally
{
   if (lockTaken) Monitor.Exit(sync);
}
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • thanks. That's a good way too! Does it work well with async/await? Await is not allowed within a SyncLock and I would have thought this seems pretty close to a lock. – Charles Aug 13 '14 at 22:21
  • 1
    @Charles It works, but it's very dangerous - see: http://stackoverflow.com/a/7612714/65358 – Reed Copsey Aug 13 '14 at 22:28
  • That was my concern. I assumed that because SemaphoreSlim has an Async WaitAsync method it is safe to place some await calls between the WaitAsync/Release but do you think there is a similar risk? – Charles Aug 13 '14 at 22:32
  • @Charles Anything that's giving you blocking semantics has the same issue if you try to await within it... Read that post ;) – Reed Copsey Aug 13 '14 at 22:39
  • For now I have to downvote this -- the question talks about async/await, and this will not really work right for async/await (as you point out) – Mark Sowul Apr 14 '15 at 13:54
  • @MarkSowul The exact same issue occurs with any synchronization primitive (including SemaphoreSlim) - it's not a matter of which class you use, but the way async/await works. It can work, but it's dangerous - but the same exact issues occur with your solution. – Reed Copsey Apr 14 '15 at 19:33
  • Deadlocks, yes; thread re-entrancy, no. (Enter the lock on one thread, await, continue on another thread; or, another await continues on your thread after you've entered the lock and awaited) – Mark Sowul Apr 14 '15 at 20:48
  • Enters every time for me, because my async method is called from the Dispatcher-Thread every time! – JCH2k Aug 30 '17 at 18:24