public async Task WaitSignaledAsync_should_not_continue_on_signal_thread() { var cancelationTokenSource = new CancellationTokenSource(); var semaphore = new SemaphoreSlimSignalable(0); var waitStartedEvent = new ManualResetEventSlim(false); var signalThreadTerminated = false; var signalThread = SignalThread(); for (int i = 0; i < 100; i++) { semaphore.Reset(); waitStartedEvent.Reset(); var waitSignaledTask = WaitSignaledTask(); await waitSignaledTask; waitSignaledTask.Result.Should().NotBe(signalThread.ManagedThreadId); } Volatile.Write(ref signalThreadTerminated, true); waitStartedEvent.Set(); signalThread.Join(100); async Task <int> WaitSignaledTask() { await Task.Yield(); var waitTask = semaphore.WaitSignaledAsync(Timeout.InfiniteTimeSpan, cancelationTokenSource.Token); waitStartedEvent.Set(); var waitResult = await waitTask; waitResult.Should().Be(SemaphoreSlimSignalable.SemaphoreWaitResult.Signaled); return(Thread.CurrentThread.ManagedThreadId); } Thread SignalThread() { var thread = new Thread(_ => { while (!Volatile.Read(ref signalThreadTerminated)) { waitStartedEvent.Wait(); waitStartedEvent.Reset(); semaphore.Signal(); } }); thread.IsBackground = true; thread.Start(); return(thread); } }
// private methods private Task <SemaphoreSlimSignalable.SemaphoreWaitResult[]> WaitAsync( SemaphoreSlimSignalable semaphore, bool async, bool isSignaledWait, int threadsCount, TimeSpan timeout, CancellationToken cancellationToken = default) => Task.WhenAll(CreateWaitTasks(semaphore, async, isSignaledWait, threadsCount, timeout, cancellationToken));
private Task <SemaphoreSlimSignalable.SemaphoreWaitResult>[] CreateWaitTasks( SemaphoreSlimSignalable semaphore, bool async, bool isSignaledWait, int threadsCount, TimeSpan timeout, CancellationToken cancellationToken = default) => async? TasksUtils.CreateTasks(threadsCount, _ => isSignaledWait?semaphore.WaitSignaledAsync(timeout, cancellationToken) : semaphore.WaitAsync(timeout, cancellationToken)) : TasksUtils.CreateTasksOnOwnThread(threadsCount, _ => isSignaledWait ? semaphore.WaitSignaled(timeout, cancellationToken) : semaphore.Wait(timeout, cancellationToken));
public async Task SemaphoreSlimSignalable_wait_should_timeout( [Values(true, false)] bool async, [Values(true, false)] bool isSignaledWait, [Values(5, 10)] int timeoutMS) { const int threadsCount = 4; var semaphore = new SemaphoreSlimSignalable(0); var results = await WaitAsync(semaphore, async, isSignaledWait, threadsCount, TimeSpan.FromMilliseconds(timeoutMS)); Assert(results, SemaphoreSlimSignalable.SemaphoreWaitResult.TimedOut); }
public async Task Reset_should_not_reset_non_signaled( [Values(true, false)] bool async) { const int threadsCount = 4; var semaphore = new SemaphoreSlimSignalable(0); var waitTasks = WaitAsync(semaphore, async, true, threadsCount, TimeSpan.FromSeconds(5)); semaphore.Reset(); semaphore.Signal(); var results = await waitTasks; Assert(results, SemaphoreSlimSignalable.SemaphoreWaitResult.Signaled); }
public async Task SemaphoreSlimSignalable_wait_should_enter( [Values(true, false)] bool async, [Values(true, false)] bool isSignaledWait, [Values(0, 1, 2)] int initialCount, [Values(2, 4)] int threadsCount) { var semaphore = new SemaphoreSlimSignalable(initialCount); var resultsTask = WaitAsync(semaphore, async, isSignaledWait, threadsCount, Timeout.InfiniteTimeSpan); for (int i = 0; i < threadsCount - initialCount; i++) { semaphore.Release(); } var results = await resultsTask; Assert(results, SemaphoreSlimSignalable.SemaphoreWaitResult.Entered); }
public async Task SemaphoreSlimSignalable_wait_should_cancel( [Values(true, false)] bool async, [Values(true, false)] bool isSignaledWait) { const int threadsCount = 4; var semaphore = new SemaphoreSlimSignalable(0); var cancelationTokenSource = new CancellationTokenSource(); var tasks = CreateWaitTasks(semaphore, async, isSignaledWait, threadsCount, Timeout.InfiniteTimeSpan, cancelationTokenSource.Token); cancelationTokenSource.Cancel(); foreach (var task in tasks) { var exception = await Record.ExceptionAsync(() => task); exception.Should().BeOfType <OperationCanceledException>(); } }
public async Task Reset_should_clear_signal( [Values(true, false)] bool async) { const int threadsCount = 4; var semaphore = new SemaphoreSlimSignalable(0); semaphore.Signal(); semaphore.Reset(); var waitTasks = WaitAsync(semaphore, async, true, threadsCount, TimeSpan.FromSeconds(5)); for (int i = 0; i < threadsCount; i++) { semaphore.Release(); } var results = await waitTasks; Assert(results, SemaphoreSlimSignalable.SemaphoreWaitResult.Entered); }
public async Task SemaphoreSlimSignalable_wait_should_signal( [Values(true, false)] bool async, [Values(true, false)] bool signalBeforeWait) { const int threadsCount = 4; var semaphore = new SemaphoreSlimSignalable(0); if (signalBeforeWait) { semaphore.Signal(); } var waitTask = WaitAsync(semaphore, async, true, threadsCount, Timeout.InfiniteTimeSpan); if (!signalBeforeWait) { semaphore.Signal(); } var results = await waitTask; Assert(results, SemaphoreSlimSignalable.SemaphoreWaitResult.Signaled); }
public SemaphoreSlimSignalableAwaiter(SemaphoreSlimSignalable semaphoreSlimSignalable) { _semaphoreSlimSignalable = semaphoreSlimSignalable; _enteredSemaphore = false; }