C# - AutoResetEvent 與 ManualResetEvent 控制執行緒暫停及恢復運作

C# 有兩個類別可以用來調控執行緒

  • AutoResetEvent
  • ManualResetEvent

WaitOne 暫停執行緒

AutoResetEvent.WaitOne 方法可以讓執行緒進入 Join (WaitSleepJoin) 暫停狀態

Set 繼續執行緒動作

AutoResetEvent.Set 方法可以讓暫停狀態的執行緒恢復運作 ManualResetEvent 則需要呼叫 .Set 與 .Reset

這裡舉例,在 A B 兩個任務類別中

在 任務A 執行了 WaitOne() 先讓 任務A 進入 WaitSleepJoin Block 狀態

當 任務B 執行到偶數時,就執行 Set() 將 A任務 恢復運作

class Program
{
    private Thread MissionA_Thread;
    private Thread MissionB_Thread;
    private static AutoResetEvent _AutoResetEvent = new AutoResetEvent(false);
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.ReadKey();
    }
    private void ProvideMission()
    {

        //指定委派A物件
        ThreadStart MissionA_Tg = new ThreadStart(MissionA);
        //建立A任務執行緒
        MissionA_Thread = new Thread(MissionA_Tg);
        //指定委派B物件
        ThreadStart MissionB_Tg = new ThreadStart(MissionB);
        //建立B任務執行緒
        MissionB_Thread = new Thread(MissionB_Tg);

        //啟動執行緒
        MissionA_Thread.Start();
        MissionB_Thread.Start();
    }
    //任務A
    private void MissionA()
    {
        for (int i = 0; i < 10; i++)
        {
            _AutoResetEvent.WaitOne();
            Console.WriteLine("A" + i);
            Thread.Sleep(1000);
        }
    }
    //任務B
    private void MissionB()
    {
        for (int i = 0; i < 10; i++)
        {
            if (i % 2 == 0)
            {
                _AutoResetEvent.Set();
            }
            Console.WriteLine("B" + i);
            Thread.Sleep(2000);
        }
    }
}

若是 ManualResetEvent 則需要再多加一次 Reset()

class Program
{
    private Thread MissionA_Thread;
    private Thread MissionB_Thread;
    private static ManualResetEvent _ManualResetEvent = new ManualResetEvent(false);
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.ReadKey();
    }
    private void ProvideMission()
    {

        //指定委派A物件
        ThreadStart MissionA_Tg = new ThreadStart(MissionA);
        //建立A任務執行緒
        MissionA_Thread = new Thread(MissionA_Tg);
        //指定委派B物件
        ThreadStart MissionB_Tg = new ThreadStart(MissionB);
        //建立B任務執行緒
        MissionB_Thread = new Thread(MissionB_Tg);

        //啟動執行緒
        MissionA_Thread.Start();
        MissionB_Thread.Start();
    }
    //任務A
    private void MissionA()
    {
        for (int i = 0; i < 10; i++)
        {
            _ManualResetEvent.WaitOne();
            Console.WriteLine("A" + i);
            Thread.Sleep(1000);
        }
    }
    //任務B
    private void MissionB()
    {
        for (int i = 0; i < 10; i++)
        {
            if (i % 2 == 0)
            {
                _ManualResetEvent.Set();
                _ManualResetEvent.Reset();
            }
            Console.WriteLine("B" + i);
            Thread.Sleep(2000);
        }
    }
}

判斷 WaitOne

在實際應用時,會先判斷 WaitOne 的狀態,確定有進入暫停狀態,才進行 Set


if (_AutoResetEvent.WaitOne(0) == false){}
    _AutoResetEvent.Set();
}

範例

class Program
{
    private Thread MissionA_Thread;
    private Thread MissionB_Thread;
    private static AutoResetEvent _AutoResetEvent = new AutoResetEvent(false);
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.ReadKey();
    }
    private void ProvideMission()
    {

        //指定委派A物件
        ThreadStart MissionA_Tg = new ThreadStart(MissionA);
        //建立A任務執行緒
        MissionA_Thread = new Thread(MissionA_Tg);
        //指定委派B物件
        ThreadStart MissionB_Tg = new ThreadStart(MissionB);
        //建立B任務執行緒
        MissionB_Thread = new Thread(MissionB_Tg);

        //啟動執行緒
        MissionA_Thread.Start();
        MissionB_Thread.Start();
    }
    //任務A
    private void MissionA()
    {
        for (int i = 0; i < 10; i++)
        {
            _AutoResetEvent.WaitOne();
            Console.WriteLine("A" + i);
        }
    }
    //任務B
    private void MissionB()
    {
        for (int i = 0; i < 10; i++)
        {
            if (i % 2 == 0)
            {
                if(_AutoResetEvent.WaitOne(0)== false)
                {
                    _AutoResetEvent.Set();
                }
            }
            Console.WriteLine("B" + i);
            Thread.Sleep(2000);
        }
    }
}