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);
    }
示例#3
0
文件: Semaphore.cs 项目: Baptista/PC
    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;
    }