利用ManualResetEvent處理多執行緒同步作業

利用設定ManualResetEvent的信號來控制多執行緒,等到多執行緒都同時完成某件事之後,才回到主要執行緒進行後續程式流程。這就是所謂的多執行緒同步

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Threading;

namespace ResetEventTest
{
    class Program
    {
        /*
         * reference:https://gmpg.org/xfn/11
         */

        private static ManualResetEvent mre_1 = new ManualResetEvent(false);
        private static ManualResetEvent mre_2 = new ManualResetEvent(false);

        static void Main(string[] args)
        {
            Console.WriteLine("\nStart 10 named threads that block on a ManualResetEvent:\n");

            for (int i = 0; i <= 10; i++)
            {
                Thread t = new Thread(ThreadProc_1);
                t.Name = /*"Thread_" +*/ i.ToString();
                t.Start();  //開始線程                
            }
            Thread.Sleep(10000);
            Console.WriteLine("\n Waiting for 10Seconds..... \n");
            
            
            for (int i = 11; i <= 13; i++)
            {
                Thread t = new Thread(ThreadProc_2);
                t.Name = /*"Thread_" +*/ i.ToString();
                t.Start();  //開始線程
            }
            Thread.Sleep(120000);
            Console.WriteLine("\n Waiting for 120Seconds..... \n");               
        }

        private static void ThreadProc_1()
        {
            string name = Thread.CurrentThread.Name;
            Console.WriteLine("Thread " + name + " starts and calls mre.WaitOne()");
            if (Convert.ToInt16(name) % 2 == 0)
            {                
                mre_2.WaitOne();//執行緒2.4.6.8.10綁定mre_2,並阻塞MRE       
            }
            else
            {                
                mre_1.Set();//執行緒1.3.5.7.9綁定mre_1,開啟mre_1綠燈
            }
            Console.WriteLine("Thread " + name + " end mre.WaitOne()");
        }

        private static void ThreadProc_2()
        {
            string name = Thread.CurrentThread.Name;
            Console.WriteLine("Thread " + name + " starts and calls mre.WaitOne()");
            if (Convert.ToInt16(name) % 2 == 0)
            {
                mre_2.Set();//執行緒12綁定mre_2,開啟mre_2綠燈。執行緒2.4.6.8.10繼續執行line55
            }
            else
            {
                mre_1.Set();//執行緒11.13綁定mre_1,開啟mre_1綠燈
            }
            Console.WriteLine("Thread " + name + " end mre.WaitOne()");
        }
    }
}

執行結果:
 

第一個迴圈new出10個執行緒,執行緒1.3.5.7.9從MRE_1取得控制信號。執行緒2.4.6.8.10從MRE_2取得控制信號。

MRE_1信號為Set(),所以執行緒1.3.5.7.9動作不會被中止

成功執行Console.WriteLine("Thread " + name + " end ThreadProc_1 mre.WaitOne()");

因為MRE_2信號為WaitOne(),執行緒會被阻塞,所以執行緒2.4.6.8.10動作被中止

無法執行Console.WriteLine("Thread " + name + " end ThreadProc_1 mre.WaitOne()");

 

第二個迴圈new出3個執行緒,執行緒11.13從MRE_1取得控制信號。執行緒12從MRE_2取得控制信號。

MRE_1信號狀態為Set(),所以執行緒11.13動作不會被中止

成功執行Console.WriteLine("Thread " + name + " end ThreadProc_2 mre.WaitOne()");

MRE_2信號狀態為Set(),所以執行緒12動作不會被中止

成功執行Console.WriteLine("Thread " + name + " end ThreadProc_2 mre.WaitOne()");

由於MRE_2的信號由WaitOne()變更為Set(),故原本在ThreadProc_1被中止動作的執行緒2.4.6.8.10解除中止

繼續往下執行Console.WriteLine("Thread " + name + " end ThreadProc_1 mre.WaitOne()");