// use semaphore in a producer/consumer context using asynchronous APM acquires private static bool TestSemaphoreInAApmProducerConsumerContext() { const int RUN_TIME = 30 * 1000; const int EXIT_TIME = 50; const int PRODUCER_THREADS = 10; const int CONSUMER_THREADS = 20; const int QUEUE_SIZE = PRODUCER_THREADS * 4; const int MIN_TIMEOUT = 0; const int MAX_TIMEOUT = 50; const int MIN_CANCEL_INTERVAL = 50; const int MAX_CANCEL_INTERVAL = 100; const int MIN_PAUSE_INTERVAL = 10; const int MAX_PAUSE_INTERVAL = 100; const int PRODUCTION_ALIVE = 100; const int CONSUMER_ALIVE = 100; Thread[] pthrs = new Thread[PRODUCER_THREADS]; Thread[] cthrs = new Thread[CONSUMER_THREADS]; int[] productions = new int[PRODUCER_THREADS]; int[] productionCancellations = new int[PRODUCER_THREADS]; int[] consumptions = new int[CONSUMER_THREADS]; int[] consumptionTimeouts = new int[CONSUMER_THREADS]; bool exit = false; BlockingQueue_ <String> queue = new BlockingQueue_ <String>(QUEUE_SIZE); // Create and start consumer threads. for (int i = 0; i < CONSUMER_THREADS; i++) { int ctid = i; cthrs[i] = new Thread(() => { Random rnd = new Random(ctid); do { var ar = queue.BeginTake(rnd.Next(MIN_TIMEOUT, MAX_TIMEOUT), CancellationToken.None, null, null); try { while (!ar.IsCompleted) { Thread.Sleep(10); } } catch (ThreadInterruptedException) { break; } catch (Exception ex) { Console.WriteLine("***Exception: {0}: {1}", ex.GetType(), ex.Message); break; } finally { if (ar.IsCompleted) { if (queue.EndTake(ar) != null) { consumptions[ctid]++; } else { consumptionTimeouts[ctid]++; } } } int sleepTime = 0; if (consumptions[ctid] % CONSUMER_ALIVE == 0) { Console.Write("[#c{0}]", ctid); sleepTime = rnd.Next(MIN_PAUSE_INTERVAL, MAX_PAUSE_INTERVAL); } try { Thread.Sleep(sleepTime); } catch (ThreadInterruptedException) { break; } } while (!Volatile.Read(ref exit)); }); cthrs[i].Priority = ThreadPriority.Highest; cthrs[i].Start(); } // Create and start producer threads. for (int i = 0; i < PRODUCER_THREADS; i++) { int ptid = i; pthrs[i] = new Thread(() => { Random rnd = new Random(ptid); CancellationTokenSource cts = new CancellationTokenSource(rnd.Next(MIN_CANCEL_INTERVAL, MAX_CANCEL_INTERVAL)); do { using (var done = new ManualResetEventSlim(false)) { queue.BeginPut(rnd.Next().ToString(), Timeout.Infinite, cts.Token, (ar) => { try { queue.EndPut(ar); productions[ptid]++; } catch (OperationCanceledException) { productionCancellations[ptid]++; cts.Dispose(); cts = new CancellationTokenSource(rnd.Next(MIN_CANCEL_INTERVAL, MAX_CANCEL_INTERVAL)); } finally { done.Set(); } }, null); try { done.Wait(); } catch (ThreadInterruptedException) { break; } } int sleepTime = 0; if (consumptions[ptid] % PRODUCTION_ALIVE == 0) { Console.Write("[#p{0}]", ptid); sleepTime = rnd.Next(MIN_PAUSE_INTERVAL, MAX_PAUSE_INTERVAL); } try { Thread.Sleep(sleepTime); } catch (ThreadInterruptedException) { break; } } while (!Volatile.Read(ref exit)); }); pthrs[i].Start(); } // run the test for a while int endTime = Environment.TickCount + RUN_TIME; do { Thread.Sleep(50); if (Console.KeyAvailable) { Console.Read(); break; } } while (Environment.TickCount < endTime); Volatile.Write(ref exit, true); Thread.Sleep(EXIT_TIME); // Wait until all producer have been terminated. int sumProductions = 0; for (int i = 0; i < PRODUCER_THREADS; i++) { if (pthrs[i].IsAlive) { pthrs[i].Interrupt(); } pthrs[i].Join(); sumProductions += productions[i]; } int sumConsumptions = 0; // Wait until all consumer have been terminated. for (int i = 0; i < CONSUMER_THREADS; i++) { if (cthrs[i].IsAlive) { cthrs[i].Interrupt(); } cthrs[i].Join(); sumConsumptions += consumptions[i]; } // Display consumer results Console.WriteLine("\nConsumer counters:"); for (int i = 0; i < CONSUMER_THREADS; i++) { if (i != 0 && i % 4 == 0) { Console.WriteLine(); } else if (i != 0) { Console.Write(' '); } Console.Write("[#c{0:D2}: {1,4}/{2, 3}]", i, consumptions[i], consumptionTimeouts[i]); } // consider not consumed productions sumConsumptions += queue.Count; Console.WriteLine("\nProducer counters:"); for (int i = 0; i < PRODUCER_THREADS; i++) { if (i != 0 && i % 4 == 0) { Console.WriteLine(); } else if (i != 0) { Console.Write(' '); } Console.Write("[#p{0:D2}: {1,4}/{2, 3}]", i, productions[i], productionCancellations[i]); } Console.WriteLine("\n--productions: {0}, consumptions: {1}", sumProductions, sumConsumptions); return(sumConsumptions == sumProductions); }
// use semaphore in a producer/consumer context using asynchronous TAP acquires private static bool TestSemaphoreInATapProducerConsumerContext() { const int RUN_TIME = 30 * 1000; const int EXIT_TIME = 50; const int PRODUCER_THREADS = 10; const int CONSUMER_THREADS = 20; const int QUEUE_SIZE = PRODUCER_THREADS * 4; const int MIN_PAUSE_INTERVAL = 10; const int MAX_PAUSE_INTERVAL = 100; const int PRODUCTION_ALIVE = 100; const int CONSUMER_ALIVE = 100; Thread[] pthrs = new Thread[PRODUCER_THREADS]; Thread[] cthrs = new Thread[CONSUMER_THREADS]; int[] productions = new int[PRODUCER_THREADS]; int[] consumptions = new int[CONSUMER_THREADS]; bool exit = false; BlockingQueue_ <String> queue = new BlockingQueue_ <String>(QUEUE_SIZE); // Create and start consumer threads. for (int i = 0; i < CONSUMER_THREADS; i++) { int ctid = i; cthrs[i] = new Thread(() => { Random rnd = new Random(ctid); do { try { var item = queue.TakeAsync().Result; consumptions[ctid]++; } catch (ThreadInterruptedException) { break; } int sleepTime = 0; if (consumptions[ctid] % CONSUMER_ALIVE == 0) { Console.Write("[#c{0}]", ctid); sleepTime = rnd.Next(MIN_PAUSE_INTERVAL, MAX_PAUSE_INTERVAL); } try { Thread.Sleep(sleepTime); } catch (ThreadInterruptedException) { break; } } while (!Volatile.Read(ref exit)); }); cthrs[i].Priority = ThreadPriority.Highest; cthrs[i].Start(); } // Create and start producer threads. for (int i = 0; i < PRODUCER_THREADS; i++) { int ptid = i; pthrs[i] = new Thread(() => { Random rnd = new Random(ptid); do { try { queue.PutAsync(rnd.Next().ToString()).Wait(); productions[ptid]++; } catch (ThreadInterruptedException) { break; } int sleepTime = 0; if (consumptions[ptid] % PRODUCTION_ALIVE == 0) { Console.Write("[#p{0}]", ptid); sleepTime = rnd.Next(MIN_PAUSE_INTERVAL, MAX_PAUSE_INTERVAL); } try { Thread.Sleep(sleepTime); } catch (ThreadInterruptedException) { break; } } while (!Volatile.Read(ref exit)); }); pthrs[i].Start(); } // run the test for a while int endTime = Environment.TickCount + RUN_TIME; do { Thread.Sleep(50); if (Console.KeyAvailable) { Console.Read(); break; } } while (Environment.TickCount < endTime); Volatile.Write(ref exit, true); Thread.Sleep(EXIT_TIME); // Wait until all producer have been terminated. int sumProductions = 0; for (int i = 0; i < PRODUCER_THREADS; i++) { if (pthrs[i].IsAlive) { pthrs[i].Interrupt(); } pthrs[i].Join(); sumProductions += productions[i]; } int sumConsumptions = 0; // Wait until all consumer have been terminated. for (int i = 0; i < CONSUMER_THREADS; i++) { if (cthrs[i].IsAlive) { cthrs[i].Interrupt(); } cthrs[i].Join(); sumConsumptions += consumptions[i]; } // Display consumer results Console.WriteLine("\nConsumer counters:"); for (int i = 0; i < CONSUMER_THREADS; i++) { if (i != 0 && i % 4 == 0) { Console.WriteLine(); } else if (i != 0) { Console.Write(' '); } Console.Write("[#c{0:D2}: {1,4}]", i, consumptions[i]); } // consider not consumed productions sumConsumptions += queue.Count; Console.WriteLine("\nProducer counters:"); for (int i = 0; i < PRODUCER_THREADS; i++) { if (i != 0 && i % 4 == 0) { Console.WriteLine(); } else if (i != 0) { Console.Write(' '); } Console.Write("[#p{0:D2}: {1,4}]", i, productions[i]); } Console.WriteLine("\n--productions: {0}, consumptions: {1}", sumProductions, sumConsumptions); return(sumConsumptions == sumProductions); }