private static bool TestSemaphoreAsLock() { const int MIN_ACQUIRE_TIMEOUT = 5; const int MAX_ACQUIRE_TIMEOUT = 50; const int MAX_CRITICAL_SECTION_TIME = 5; const int JOIN_TIMEOUT = 50; const int RUN_TIME = 10 * 1000; const int THREADS = 10; Thread[] tthrs = new Thread[THREADS]; int[] privateCounters = new int[THREADS]; int[] timeouts = new int[THREADS]; int sharedCounter = 0; Semaphore_ lockSem = new Semaphore_(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(tid); Console.WriteLine($"-> #{tid:D2} starting..."); do { try { do { if (lockSem.Acquire(rnd.Next(MIN_ACQUIRE_TIMEOUT, MAX_ACQUIRE_TIMEOUT))) { break; } if (++timeouts[tid] % 100 == 0) { Console.Write('.'); } } while (true); try { Interlocked.Increment(ref sharedCounter); if (++privateCounters[tid] % 10 == 0) { Console.Write($"[#{tid:D2}]"); } Thread.Sleep(rnd.Next(MAX_CRITICAL_SECTION_TIME)); } finally { lockSem.Release(); } } catch (ThreadInterruptedException) { /* * if (tid == 0) * do {} while (true); */ goto exit; } } while (!IsCurrentThreadInterrupted()); exit: Console.WriteLine($"<- #{tid:00} exiting..."); }); tthrs[i].IsBackground = true; tthrs[i].Start(); } // run the test threads for a while... Thread.Sleep(RUN_TIME); // Interrupt each test thread and wait for a while until it finished. int stillRunning = 0; for (int i = 0; i < THREADS; i++) { tthrs[i].Interrupt(); if (!tthrs[i].Join(JOIN_TIMEOUT)) { stillRunning++; } } if (stillRunning > 0) { Console.WriteLine("\n*** failure: {0} test thread(s) did not answer to interruption", stillRunning); return(false); } // All threads finished - compute results Console.WriteLine("\nPrivate counters:\n"); int sum = 0; for (int i = 0; i < THREADS; i++) { sum += privateCounters[i]; if ((i % 5) == 0) { Console.WriteLine(); } else { Console.Write(' '); } Console.Write($"[#{i:00}:{privateCounters[i],4}/{timeouts[i]}]"); } Console.WriteLine($"\n--shared aquisitions: {sharedCounter}, private acquisitions: {sum}"); return(sum == sharedCounter); }
private static bool TestSemaphoreInAProducerConsumerContext() { const int MAX_PRODUCE_TIME = 2; const int MAX_CONSUME_TIME = 3; const int RUN_TIME = 10 * 1000; const int JOIN_TIMEOUT = 50; const int PRODUCER_THREADS = 5; const int CONSUMER_THREADS = 10; Thread[] cthrs = new Thread[CONSUMER_THREADS]; Thread[] pthrs = new Thread[PRODUCER_THREADS]; int[] consumerCounters = new int[CONSUMER_THREADS]; int[] producerCounters = new int[PRODUCER_THREADS]; // Using our semaphore... Semaphore_ freeSem = new Semaphore_(1); Semaphore_ dataSem = new Semaphore_(0); // Create and start consumer threads. for (int i = 0; i < CONSUMER_THREADS; i++) { int tid = i; cthrs[i] = new Thread(() => { Random rnd = new Random(tid); do { try { dataSem.Acquire(); try { if (++consumerCounters[tid] % 10 == 0) { Console.Write($"[#c{tid:D2}]"); } Thread.Sleep(rnd.Next(MAX_CONSUME_TIME)); } finally { freeSem.Release(); } } catch (ThreadInterruptedException) { break; } } while (!IsCurrentThreadInterrupted()); }); cthrs[i].IsBackground = true; cthrs[i].Priority = ThreadPriority.Highest; cthrs[i].Start(); } // Create and start producer threads. for (int i = 0; i < PRODUCER_THREADS; i++) { int tid = i; pthrs[i] = new Thread(() => { Random rnd = new Random(tid + CONSUMER_THREADS); do { try { freeSem.Acquire(); try { if (++producerCounters[tid] % 10 == 0) { Console.Write($"[#p{tid:D2}]"); } Thread.Sleep(rnd.Next(MAX_PRODUCE_TIME)); } finally { dataSem.Release(); } } catch (ThreadInterruptedException) { break; } } while (!IsCurrentThreadInterrupted()); }); pthrs[i].IsBackground = true; pthrs[i].Start(); } // run the test for a while Thread.Sleep(RUN_TIME); // Interrupt each consumer thread and wait for a while until it finished. int stillRunning = 0; for (int i = 0; i < CONSUMER_THREADS; i++) { cthrs[i].Interrupt(); if (!cthrs[i].Join(JOIN_TIMEOUT)) { stillRunning++; } } // Interrupt each producer thread and wait for a while until it finished. for (int i = 0; i < PRODUCER_THREADS; i++) { pthrs[i].Interrupt(); if (!pthrs[i].Join(JOIN_TIMEOUT)) { stillRunning++; } } if (stillRunning > 0) { Console.WriteLine($"\n*** failure: {stillRunning} test thread(s) did not answer to interruption"); return(false); } // Compute results Console.WriteLine("\nConsumer counters:"); int consumptions = 0; for (int i = 0; i < CONSUMER_THREADS; i++) { consumptions += consumerCounters[i]; if (i != 0) { if (i % 4 == 0) { Console.WriteLine(); } else { Console.Write(' '); } } Console.Write($"#c[{i:00}: {consumerCounters[i],4}]"); } if (dataSem.TryAcquire()) { consumptions++; } Console.WriteLine("\nProducer counters:"); int productions = 0; for (int i = 0; i < PRODUCER_THREADS; i++) { productions += producerCounters[i]; if (i != 0) { if (i % 4 == 0) { Console.WriteLine(); } else { Console.Write(' '); } } Console.Write($"[#p{i:00}: {producerCounters[i],4}]"); } Console.WriteLine($"\n--productions: {productions}, consumptions: {consumptions}"); return(consumptions == productions); }
private static bool TestSemaphoreAsLock() { const int MIN_TIMEOUT = 0; const int MAX_TIMEOUT = 10; const int RUN_TIME = 10000; const int THREADS = 50; Thread[] tthrs = new Thread[THREADS]; int[] privateCounters = new int[THREADS]; int sharedCounter = 0; Semaphore_ lockSem = new Semaphore_(1); for (int i = 0; i < THREADS; i++) { int tid = i; tthrs[i] = new Thread(() => { Random rnd = new Random(tid); int endTime = Environment.TickCount + RUN_TIME; do { lockSem.Acquire(); sharedCounter++; lockSem.Release(); if ((++privateCounters[tid] % 100) == 0) { Console.Write("[#{0}: {1}]", tid, privateCounters[tid]); } else { Thread.Sleep(rnd.Next(MIN_TIMEOUT, MAX_TIMEOUT)); } } while (Environment.TickCount < endTime); }); tthrs[i].Start(); } // Wait until all threads have been terminated. for (int i = 0; i < THREADS; i++) tthrs[i].Join(); // Compute results Console.WriteLine("\nPrivate counters:\n"); int sum = 0; for (int i = 0; i < THREADS; i++) { sum += privateCounters[i]; if ((i % 5) == 0) Console.WriteLine(); else Console.Write(' '); Console.Write("[#{0}: {1,4}]", i, privateCounters[i]); } return sum == sharedCounter; }