2019年3月11日 星期一

C# 執行緒(Thread)的AutoResetEvent及ManualResetEvent探討

AutoResetEvent及ManualResetEvent都是可以讓執行緒藉由發出訊號,與彼此進行通訊,控制執行緒暫停或繼續,就像高速公路上的閘道一樣,控制關閉或通行,初始的bool變量,來指明閘道的狀態,true表示可以通行、false表示不可通行。閘道主要有三個方法:WaitOne、Set和Reset。他們就像閘道一樣控制開關,控制執行緒暫停或繼續,Set()表示繼續、WaitOne表示暫停。而這兩者的主要差別在於:

AutoResetEvent

  • 只會給一個執行緒發送訊號
  • Set()後狀態設置會自動設置成false
ManualResetEvent
  • 給所有執行續發送訊號
  • Set()後狀態設置會設置成true,需要手動呼叫Reset()將狀態改為false,在狀態為true時候,WaitOne是沒有作用的
AutoResetEvent.Set() = ManualResetEvent.Set() + ManualResetEvent.Reset();


以下是程式碼:

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        private static AutoResetEvent _guard1Event = new AutoResetEvent(false);
        private static AutoResetEvent _guard2Event = new AutoResetEvent(false);
        private static ManualResetEvent _gateEvent = new ManualResetEvent(false);

        static void Main(string[] args)
        {
            /** *******************
             * Thread的AutoResetEvent機制
             * ********************/
            var t = new Thread(() => Process(10));
            t.Start();

            Console.WriteLine("1.Waiting for another thread completed its work.");
            //等待通行信號
            _guard2Event.WaitOne();
            Console.WriteLine("5.First operation is completed.");
            Thread.Sleep(TimeSpan.FromSeconds(5));
            //發送信號通知正在等待的Thread工作已經完成
            _guard1Event.Set();
            Console.WriteLine("6.Second operation is Starting.");
            //等待通行信號
            _guard2Event.WaitOne();
            Console.WriteLine("9.Second operation is completed.");
            Console.ReadKey();

            Console.WriteLine("---------------------------------");


            /** *******************
             * Thread的ManualResetEvent機制
             * ********************/
            var t1 = new Thread(() => TravelThroughGates("thread 1",5));
            var t2 = new Thread(() => TravelThroughGates("thread 2", 7));
            var t3 = new Thread(() => TravelThroughGates("thread 3", 9));

            t1.Start();
            t2.Start();
            t3.Start();
            Thread.Sleep(TimeSpan.FromSeconds(5));
            Console.WriteLine($"the gates are open now.");
            _gateEvent.Set();
            Console.WriteLine($"the gates have been closed.");
            _gateEvent.Reset();
            Thread.Sleep(TimeSpan.FromSeconds(5));
            Console.WriteLine($"the gates are open for a while.");
            _gateEvent.Set();
            Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.WriteLine($"the gates have been closed.");
            _gateEvent.Reset();
            Console.ReadKey();
        }

        static void Process(int seconds)
        {
            Console.WriteLine("2.Start running");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            Console.WriteLine("3.Work is done.");
            //發送信號通知可通行
            _guard2Event.Set();
            Console.WriteLine("4.Waiting for a main thread completed its work.");
            //等待信號主程序給通行信號
            _guard1Event.WaitOne();
            Console.WriteLine("7.Start second operation");
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            Console.WriteLine("8.Work is done.");
            _guard2Event.Set();
        }

        static void TravelThroughGates(string threadName, int seconds)
        {
            Console.WriteLine($"{threadName} is falling asleep");
            //開放通行
            _gateEvent.Set();
            Thread.Sleep(TimeSpan.FromSeconds(seconds));
            Console.WriteLine($"{threadName} is waiting for gates to open");
            //等待通行信號
            _gateEvent.WaitOne();
            Console.WriteLine($"{threadName} entered the gates");
        }
    }
}

這是執行結果:


沒有留言:

張貼留言