/// <summary> /// Test SemaphoreSlimDynamic WaitAsync /// </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_InternalAsync (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.WaitAsync((TimeSpan)timeout).Result; } else { result = semaphore.WaitAsync((int)timeout).Result; } 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); }
/// <summary> /// Test SemaphoreSlimDynamic AvailableWaitHandle property /// </summary> /// <param name="initial">The initial semaphore count</param> /// <param name="maximum">The maximum semaphore count</param> /// <param name="action">SemaphoreSlimDynamic action to be called before WaitHandle</param> /// <param name="state">The expected wait handle state</param> /// <returns>True if the test succeeded, false otherwise</returns> private static void RunSemaphoreSlimDynamicTest7_AvailableWaitHandle_Internal(int initial, int maximum, Actions?action, bool state) { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(0, initial, maximum); CallSemaphoreAction(semaphore, action, null); Assert.NotNull(semaphore.AvailableWaitHandle); Assert.Equal(state, semaphore.AvailableWaitHandle.WaitOne(0)); }
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 CurrentCount property /// </summary> /// <param name="initial">The initial semaphore count</param> /// <param name="maximum">The maximum semaphore count</param> /// <param name="action">SemaphoreSlimDynamic action to be called before CurrentCount</param> /// <returns>True if the test succeeded, false otherwise</returns> private static void RunSemaphoreSlimDynamicTest5_CurrentCount_Internal(int initial, int maximum, Actions?action) { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(0, initial, maximum); CallSemaphoreAction(semaphore, action, null); if (action == null) { Assert.Equal(initial, semaphore.CurrentCount); } else { Assert.Equal(initial + (action == Actions.Release ? 1 : -1), semaphore.CurrentCount); } }
/// <summary> /// Test SemaphoreSlimDynamic Dispose /// </summary> /// <param name="initial">The initial semaphore count</param> /// <param name="maximum">The maximum semaphore count</param> /// <param name="action">SemaphoreSlimDynamic action to be called after Dispose</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 RunSemaphoreSlimDynamicTest4_Dispose_Internal(int initial, int maximum, Actions?action, Type exceptionType) { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(0, initial, maximum); try { semaphore.Dispose(); CallSemaphoreAction(semaphore, action, null); } catch (Exception ex) { Assert.NotNull(exceptionType); Assert.IsType(exceptionType, ex); } }
public static void RunSemaphoreSlimDynamicTest8_ConcWaitAsyncAndRelease(int initial, int maximum, int waitThreads, int releaseThreads, int succeededWait, int failedWait, int finalCount, int timeout) { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(0, initial, maximum); Task[] tasks = new Task[waitThreads + releaseThreads]; int succeeded = 0; int failed = 0; ManualResetEvent mre = new ManualResetEvent(false); // launch threads for (int i = 0; i < tasks.Length; i++) { if (i < waitThreads) { tasks[i] = Task.Run(async delegate { mre.WaitOne(); if (await semaphore.WaitAsync(timeout)) { Interlocked.Increment(ref succeeded); } else { Interlocked.Increment(ref failed); } }); } else { tasks[i] = Task.Run(delegate { mre.WaitOne(); semaphore.Release(); }); } } mre.Set(); //wait work to be done; Task.WaitAll(tasks); Assert.Equal(succeededWait, succeeded); Assert.Equal(failedWait, failed); Assert.Equal(finalCount, semaphore.CurrentCount); }
/// <summary> /// Test SemaphoreSlimDynamic Release /// </summary> /// <param name="initial">The initial semaphore count</param> /// <param name="maximum">The maximum semaphore count</param> /// <param name="releaseCount">The release count for the release method</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 RunSemaphoreSlimDynamicTest2_Release_Internal (int initial, int maximum, int releaseCount, Type exceptionType) { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(0, initial, maximum); try { int oldCount = semaphore.Release(releaseCount); Assert.Equal(initial, oldCount); Assert.Equal(initial + releaseCount, semaphore.CurrentCount); } catch (Exception ex) { Assert.NotNull(exceptionType); Assert.IsType(exceptionType, ex); } }
/// <summary> /// Test SemaphoreSlimDynamic constructor /// </summary> /// <param name="min">The minimum semaphore count</param> /// <param name="initial">The initial semaphore count</param> /// <param name="maximum">The maximum semaphore count</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 RunSemaphoreSlimDynamicTest0_Ctor_Internal(int min, int initial, int maximum, Type exceptionType) { string methodFailed = "RunSemaphoreSlimDynamicTest0_Ctor_Internal(" + min + "," + initial + "," + maximum + "): FAILED. "; Exception exception = null; try { SemaphoreSlimDynamic semaphore = new SemaphoreSlimDynamic(min, initial, maximum); Assert.Equal(initial, semaphore.CurrentCount); } catch (Exception ex) { Assert.NotNull(exceptionType); Assert.IsType(exceptionType, ex); exception = ex; } }
/// <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); }