// take activating a timeout public T Take(int timeout) { if (!filledSlots.Wait(timeout)) { return(null); // time out } T item; lock (room) { item = room[takeIdx++ % queueSize]; } freeSlots.Release(); return(item); }
// test semaphore fairness asynchronous private static bool TestSemaphoreFairnessAsync() { const int SETUP_TIME = 50; const int THREADS = 50; const int MIN_TIMEOUT = 5; const int MAX_TIMEOUT = 20; Thread[] tthrs = new Thread[THREADS]; int[] privateCounters = new int[THREADS]; ManualResetEventSlim startEvent = new ManualResetEventSlim(false); var sem = new SemaphoreAsync(THREADS, THREADS); int totalTimeouts = 0; bool exit = false; for (int i = 0; i < THREADS; i++) { int tid = i; tthrs[i] = new Thread(() => { Random random = new Random(tid); // Wait until start event is set startEvent.Wait(); do { do { if (sem.WaitAsyncEx(random.Next(MIN_TIMEOUT, MAX_TIMEOUT), CancellationToken.None).Result) { break; } Interlocked.Increment(ref totalTimeouts); } while (true); Thread.Yield(); sem.Release(); if ((++privateCounters[tid] % 100) == 0) { Console.Write("[#{0}]", tid); } } while (!Volatile.Read(ref exit)); }); tthrs[i].Start(); } // Wait until all test threads have been started and then set the // start event. Thread.Sleep(SETUP_TIME); startEvent.Set(); do { Thread.Sleep(50); } while (!Console.KeyAvailable); Console.Read(); Volatile.Write(ref exit, true); // Wait until all threads have been terminated. for (int i = 0; i < THREADS; i++) { tthrs[i].Join(); } // Show results int total = 0; Console.WriteLine("\nPrivate counters:"); for (int i = 0; i < THREADS; i++) { if (i != 0 && (i % 5) == 0) { Console.WriteLine(); } Console.Write("[#{0:D2}:{1,4}]", i, privateCounters[i]); total += privateCounters[i]; } Console.WriteLine("\n-- total acquisitions/releases: {0}, timeouts: {1}", total, totalTimeouts); return(true); }