public async Task DeduplicateBasicScenario() { var gate = TaskUtilities.CreateMutex(); var winningLatch = new SemaphoreSlim(0, 1); var losingLatch = new SemaphoreSlim(0, 1); var completionLatch = new SemaphoreSlim(0, 1); var win = winningTask(); var lose = losingTask(); await Task.WhenAll(win, lose); Contract.Assert(1 == await win); Contract.Assert(4 == await lose); async Task <int> winningTask() { await Task.Yield(); await winningLatch.WaitAsync(); return(await gate.DeduplicatedOperationAsync(async (w, c) => { losingLatch.Release(); await completionLatch.WaitAsync(); return 1; }, (w, c) => { Contract.Assert(false, "This should never happen"); return Task.FromResult(2); })); } async Task <int> losingTask() { await Task.Yield(); winningLatch.Release(); await losingLatch.WaitAsync(); return(await gate.DeduplicatedOperationAsync((w, c) => { Contract.Assert(false, "This should never happen"); return Task.FromResult(3); }, (w, c) => { completionLatch.Release(); return Task.FromResult(4); })); } }
public async Task ResourceInvalidationRespectsReferenceCountBeforeShutdown() { var stopLatch = TaskUtilities.CreateMutex(taken: true); Task?outstandingTask = null; CounterCollection <ResourcePoolV2Counters>?counters = null; await RunTest <Key, Resource>(async (context, pool) => { counters = pool.Counter; var key = new Key(0); await pool.UseAsync(context, key, async wrapper => { outstandingTask = pool.UseAsync(context, key, async wrapper2 => { wrapper2.ReferenceCount.Should().Be(2); stopLatch.Release(); try { await Task.Delay(Timeout.InfiniteTimeSpan, wrapper2.ShutdownToken); } catch (TaskCanceledException) { } wrapper2.ReferenceCount.Should().Be(1); counters[ResourcePoolV2Counters.CreatedResources].Value.Should().Be(1); counters[ResourcePoolV2Counters.ReleasedResources].Value.Should().Be(0); counters[ResourcePoolV2Counters.ShutdownAttempts].Value.Should().Be(0); return(BoolResult.Success); }).ShouldBeSuccess(); using var token = await stopLatch.AcquireAsync(); wrapper.Invalidate(context); return(BoolResult.Success); }).ShouldBeSuccess(); }); Contract.AssertNotNull(counters); Contract.AssertNotNull(outstandingTask); // This should throw any exceptions that haven't been caught await outstandingTask; }
public async Task ResourceInvalidationShutsDownOutstandingOperations() { var stopLatch = TaskUtilities.CreateMutex(taken: true); Task?witnessTask = null; var witnessedCancellation = false; await RunTest <Key, Resource>(async (context, pool) => { var key = new Key(0); await pool.UseAsync(context, key, async wrapper => { await Task.Yield(); witnessTask = Task.Run(async() => { // Ensuring it doesn't run on the UseAsync call await Task.Yield(); // Allow the UseAsync call to invalidate stopLatch.Release(); // Ensure we get cancelled try { await Task.Delay(Timeout.InfiniteTimeSpan, wrapper.ShutdownToken); } catch (TaskCanceledException) { } witnessedCancellation = true; }).FireAndForgetErrorsAsync(context); using var token = await stopLatch.AcquireAsync(); wrapper.Invalidate(context); return(BoolResult.Success); }).ShouldBeSuccess(); }); Contract.AssertNotNull(witnessTask); await witnessTask; witnessedCancellation.Should().Be(true); }