Use RunContinuationsAsynchronously in SemaphoreSlim.WaitAsync (dotnet/coreclr#22686)
authorStephen Toub <stoub@microsoft.com>
Tue, 19 Feb 2019 22:35:06 +0000 (17:35 -0500)
committerGitHub <noreply@github.com>
Tue, 19 Feb 2019 22:35:06 +0000 (17:35 -0500)
commitc5a6c24ee1b339872458c9fd5a93ed4af4c47893
tree57283f7ec16c8ea7339fed033ff4295c8de51050
parentfd52651e4d8c709c09f9fb542fee1f73f109afe4
Use RunContinuationsAsynchronously in SemaphoreSlim.WaitAsync (dotnet/coreclr#22686)

SemaphoreSlim.Release shouldn't invoke arbitrary continuations as part of its invocation, so when it dequeues a task waiter and goes to complete it, rather than just calling TrySetResult, it queues the task to the thread pool to have TrySetResult invoked there.  Now that we have RunContinuationsAsynchronously, though, we can just use that functionality instead.  This has two main benefits:
1. We avoid queueing a work item entirely if there are no continuations from the task.  This might happen, for example, if the semaphore is released so quickly after waiting on it that the WaitAsync caller hasn't yet hooked up a continuation, in which case the await on the WaitAsync task will just see IsCompleted as true and continue running.
2. We avoid queueing a work item when the task represents a synchronous Wait, which happens if there's already a pending WaitAsync when Wait goes to block.  The main benefit here is avoiding potential thread pool starvation, if threads in the pool are blocked in such Waits, and previously another thread pool thread would have been needed to run the queued work item to complete the synchronous Wait.

Commit migrated from https://github.com/dotnet/coreclr/commit/e2081d0e67a1d7fedaf6303f576acef316c7bd66
src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs