// Put an item in the queue synchronously enabling timeout and cancellation public bool Put(T item, int timeout = Timeout.Infinite, CancellationToken cToken = default(CancellationToken)) { if (freeSlots.Acquire(timeout: timeout, token: cToken)) { lock (room) room[putIdx++ % capacity] = item; filledSlots.Release(); return(true); } else { return(false); } }
// test semaphore as a mutual exclusion lock using synchronous acquires private static bool TestSemaphoreAsLockSync() { const int SETUP_TIME = 50; const int RUN_TIME = 30 * 1000; int THREADS = 50; const int MIN_TIMEOUT = 1; const int MAX_TIMEOUT = 50; const int MIN_CANCEL_INTERVAL = 1; const int MAX_CANCEL_INTERVAL = 50; Thread[] tthrs = new Thread[THREADS]; int[] privateCounters = new int[THREADS]; int[] timeouts = new int[THREADS]; int[] cancellations = new int[THREADS]; int issuedInterrupts = 0; int[] sensedInterrupts = new int[THREADS]; int sharedCounter = 0; bool exit = false; ManualResetEventSlim start = new ManualResetEventSlim(); SemaphoreSlim1 _lock = new SemaphoreSlim1(1, 1); /** * Create and start acquirer/releaser threads */ for (int i = 0; i < THREADS; i++) { int tid = i; tthrs[i] = new Thread(() => { Random rnd = new Random(Thread.CurrentThread.ManagedThreadId); start.Wait(); CancellationTokenSource cts = new CancellationTokenSource(rnd.Next(MIN_CANCEL_INTERVAL, MAX_CANCEL_INTERVAL)); do { do { try { if (_lock.Acquire(timeout: rnd.Next(MIN_TIMEOUT, MAX_TIMEOUT), token: cts.Token)) { break; } timeouts[tid]++; } catch (OperationCanceledException) { cancellations[tid]++; cts.Dispose(); cts = new CancellationTokenSource(rnd.Next(MIN_CANCEL_INTERVAL, MAX_CANCEL_INTERVAL)); } catch (ThreadInterruptedException) { sensedInterrupts[tid]++; } } while (true); try { Thread.Sleep(0); } catch (ThreadInterruptedException) { sensedInterrupts[tid]++; } sharedCounter++; if (THREADS > 1) { if (rnd.Next(100) < 99) { Thread.Yield(); } else { try { Thread.Sleep(rnd.Next(MIN_TIMEOUT, MAX_TIMEOUT)); } catch (ThreadInterruptedException) { sensedInterrupts[tid]++; } } } // release the lock _lock.Release(); privateCounters[tid]++; if (THREADS > 1) { try { if ((privateCounters[tid] % 100) == 0) { Console.Write("[#{0:D2}]", tid); } } catch (ThreadInterruptedException) { sensedInterrupts[tid]++; } } } while (!Volatile.Read(ref exit)); try { Thread.Sleep(10); } catch (ThreadInterruptedException) { sensedInterrupts[tid]++; } }); tthrs[i].Start(); } Thread.Sleep(SETUP_TIME); Stopwatch sw = Stopwatch.StartNew(); start.Set(); Random grnd = new Random(Thread.CurrentThread.ManagedThreadId); int endTime = Environment.TickCount + RUN_TIME; //... do { Thread.Sleep(grnd.Next(5)); #if SEND_INTERRUPTS if (THREADS > 1) { tthrs[grnd.Next(THREADS)].Interrupt(); issuedInterrupts++; } #endif if (Console.KeyAvailable) { Console.Read(); break; } #if RUN_CONTINOUSLY } while (true); #else } while (Environment.TickCount < endTime);