/// <summary> /// Test SemaphoreSlimDynamic Wait /// </summary> /// <param name="initial">The initial semaphore count</param> /// <param name="maximum">The maximum semaphore count</param> /// <param name="timeout">The timeout parameter for the wait method, it must be either int or TimeSpan</param> /// <param name="returnValue">The expected wait return value</param> /// <param name="exceptionType">The type of the thrown exception in case of invalid cases, /// null for valid cases</param> /// <returns>True if the test succeeded, false otherwise</returns> private static void RunSemaphoreSlimDynamicTest1_Wait_Internal (int initial, int maximum, object timeout, bool returnValue, Type exceptionType) { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(0, initial, maximum); try { bool result = false; if (timeout is TimeSpan) { result = semaphore.Wait((TimeSpan)timeout); } else { result = semaphore.Wait((int)timeout); } Assert.Equal(returnValue, result); if (result) { Assert.Equal(initial - 1, semaphore.CurrentCount); } } catch (Exception ex) { Assert.NotNull(exceptionType); Assert.IsType(exceptionType, ex); } }
/// <summary> /// Call specific SemaphoreSlimDynamic method or property /// </summary> /// <param name="semaphore">The SemaphoreSlimDynamic instance</param> /// <param name="action">The action name</param> /// <param name="param">The action parameter, null if it takes no parameters</param> /// <param name="output">The test output helper to use if available.</param> /// <param name="outputPrefix">Prefix to add to the debug output.</param> /// <returns>The action return value, null if the action returns void</returns> private static object CallSemaphoreAction (SemaphoreSlimDynamic semaphore, Actions?action, object param, ITestOutputHelper output = null, string outputPrefix = null) { output?.WriteLine($"{outputPrefix ?? string.Empty}Action {action?.ToString() ?? "Unknown"}: {param?.ToString() ?? "None"}"); if (action == Actions.Wait) { if (param is TimeSpan) { return(semaphore.Wait((TimeSpan)param)); } else if (param is int) { return(semaphore.Wait((int)param)); } semaphore.Wait(); return(null); } else if (action == Actions.WaitAsync) { if (param is TimeSpan) { return(semaphore.WaitAsync((TimeSpan)param).Result); } else if (param is int) { return(semaphore.WaitAsync((int)param).Result); } semaphore.WaitAsync().Wait(); return(null); } else if (action == Actions.Release) { if (param != null) { return(semaphore.Release((int)param)); } return(semaphore.Release()); } else if (action == Actions.Dispose) { semaphore.Dispose(); return(null); } else if (action == Actions.CurrentCount) { return(semaphore.CurrentCount); } else if (action == Actions.AvailableWaitHandle) { return(semaphore.AvailableWaitHandle); } else if (action == Actions.SetAvailableSlot) { return(semaphore.SetAvailableSlot((int)param)); } return(null); }
public static void RunSemaphoreSlimDynamicTest8_ConcWaitAndRelease(int initial, int maximum, int waitThreads, int releaseThreads, int succeededWait, int failedWait, int finalCount, int timeout) { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(0, initial, maximum); Task[] threads = new Task[waitThreads + releaseThreads]; int succeeded = 0; int failed = 0; ManualResetEvent mre = new ManualResetEvent(false); // launch threads for (int i = 0; i < threads.Length; i++) { if (i < waitThreads) { // We are creating the Task using TaskCreationOptions.LongRunning to // force usage of another thread (which will be the case on the default scheduler // with its current implementation). Without this, the release tasks will likely get // queued behind the wait tasks in the pool, making it very likely that the wait tasks // will starve the very tasks that when run would unblock them. threads[i] = new Task(delegate() { mre.WaitOne(); if (semaphore.Wait(timeout)) { Interlocked.Increment(ref succeeded); } else { Interlocked.Increment(ref failed); } }, TaskCreationOptions.LongRunning); } else { threads[i] = new Task(delegate() { mre.WaitOne(); semaphore.Release(); }); } threads[i].Start(TaskScheduler.Default); } mre.Set(); //wait work to be done; Task.WaitAll(threads); //check the number of succeeded and failed wait Assert.Equal(succeededWait, succeeded); Assert.Equal(failedWait, failed); Assert.Equal(finalCount, semaphore.CurrentCount); }
/// <summary> /// Test SemaphoreSlimDynamic WaitAsync /// The test verifies that SemaphoreSlimDynamic.Release() does not execute any user code synchronously. /// </summary> private static void RunSemaphoreSlimDynamicTest1_Wait_InternalAsync2() { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(1, 1, 1); ThreadLocal <int> counter = new ThreadLocal <int>(() => 0); bool nonZeroObserved = false; const int asyncActions = 20; int remAsyncActions = asyncActions; ManualResetEvent mre = new ManualResetEvent(false); Action <int> doWorkAsync = async delegate(int i) { await semaphore.WaitAsync(); if (counter.Value > 0) { nonZeroObserved = true; } counter.Value = counter.Value + 1; semaphore.Release(); counter.Value = counter.Value - 1; if (Interlocked.Decrement(ref remAsyncActions) == 0) { mre.Set(); } }; semaphore.Wait(); for (int i = 0; i < asyncActions; i++) { doWorkAsync(i); } semaphore.Release(); mre.WaitOne(); Assert.False(nonZeroObserved, "RunSemaphoreSlimDynamicTest1_Wait_InternalAsync2: FAILED. SemaphoreSlimDynamic.Release() seems to have synchronously invoked a continuation."); }
public static void RunSemaphoreSlimDynamicTest9_ConcurrentWaitAndWaitAsync(int syncWaiters, int asyncWaiters) { int totalWaiters = syncWaiters + asyncWaiters; var semaphore = new SemaphoreSlimDynamic(0, 0, int.MaxValue); Task[] tasks = new Task[totalWaiters]; const int ITERS = 10; int randSeed = unchecked ((int)DateTime.Now.Ticks); for (int i = 0; i < syncWaiters; i++) { tasks[i] = Task.Run(delegate { //Random rand = new Random(Interlocked.Increment(ref randSeed)); for (int iter = 0; iter < ITERS; iter++) { semaphore.Wait(); semaphore.Release(); } }); } for (int i = syncWaiters; i < totalWaiters; i++) { tasks[i] = Task.Run(async delegate { //Random rand = new Random(Interlocked.Increment(ref randSeed)); for (int iter = 0; iter < ITERS; iter++) { await semaphore.WaitAsync(); semaphore.Release(); } }); } semaphore.Release(totalWaiters / 2); Task.WaitAll(tasks); }