/// <inheritdoc/> public void Dispose() { if (isDisposed) { return; } isDisposed = true; if (leaderElector != null) { leaderElector.Dispose(); try { leaderTask.WaitWithoutAggregate(); } catch (OperationCanceledException) { // We're expecting this. } leaderElector = null; leaderTask = null; } mutex.Dispose(); GC.SuppressFinalize(this); }
public async Task Dispose_Func() { // Verify that [ObjectDisposedException] is thrown for function tasks waiting // to acquire the mutex. var mutex = new AsyncReentrantMutex(); try { // Hold the mutex for 2 seconds so the tasks below will block. var task1Acquired = false; var task2Acquired = false; var task3Acquired = false; var task1 = mutex.ExecuteFuncAsync( async() => { task1Acquired = true; await Task.Delay(TimeSpan.FromSeconds(2)); return("TASK1"); }); // Wait for [task1] to actually acquire to mutex. NeonHelper.WaitFor(() => task1Acquired, defaultTimeout); // Start two new tasks that will block. var task2 = mutex.ExecuteFuncAsync( async() => { task2Acquired = true; await Task.CompletedTask; return("TASK2"); }); var task3 = mutex.ExecuteFuncAsync( async() => { task3Acquired = true; await Task.CompletedTask; return("TASK1"); }); // Dispose the mutex. We're expecting [task1] to complete normally and // [task2] and [task3] to fail with an [OperationCancelledException] with // their actions never being invoked. mutex.Dispose(); await Assert.ThrowsAsync <ObjectDisposedException>(async() => await task2); Assert.False(task2Acquired); await Assert.ThrowsAsync <ObjectDisposedException>(async() => await task3); Assert.False(task3Acquired); await task1; Assert.True(task1Acquired); } finally { // Disposing this again shouldn't cause any trouble. mutex.Dispose(); } }