Variation of @usr's answer that solved my slightly more general problem (after quite some time going down the rathole of trying to marry AvailableWaitHandle
with Task
...)
class SemaphoreSlimExtensions
public static Task AwaitButReleaseAsync(this SemaphoreSlim s) =>
s.WaitAsync().ContinueWith(_t -> s.Release(), ct,
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default);
public static bool TryTake(this SemaphoreSlim s) =>
s.Wait(0);
In my use case, the await
is just a trigger for synchronous logic that then walks the full set - the TryTake
helper is in my case a natural way to handle the conditional acquisition of the semaphore and the processing that's contingent on that.
var sems = new[] { new SemaphoreSlim(1, 1), new SemaphoreSlim(1, 1) };
await Task.WhenAny(from s in sems select s.AwaitButReleaseAsync());
Putting it here as I believe it to be clean, clear and relatively efficient but would be happy to see improvements on it