C# Thread 執行緒

程式都會有一個主處理序

例如,在同一個主處理序,可能同時會需要送出多筆訂單、讀取大型檔案等項目要排隊

在這主要的處理序,可以額外建立新的執行緒,可以將指定的任務交給新的執行緒獨立處理

通常,需要長時運算、 等待回應的流程,就會透過建立新的執行緒來獨立運算,避免影響到其他流程

載入空間命名

using System.Threading;

ThreadStart 執行緒

首先,介紹ThreadStart,可以直接委派執行緒至無回傳值的物件

class Program
{
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.ReadKey();
    }
    //指派任務
    private void ProvideMission()
    {
        //指定委派物件
        ThreadStart MissionA_Tg = new ThreadStart(MissionA);
        //建立A任務執行緒
        Thread MissionA_Thread = new Thread(MissionA_Tg);
        MissionA_Thread.Name = "Mission A";

        //指定委派物件
        ThreadStart MissionB_Tg = new ThreadStart(MissionB);
        //建立B任務執行緒
        Thread MissionB_Thread = new Thread(MissionB_Tg);
        MissionB_Thread.Name = "Mission B";

        //啟動執行緒
        MissionA_Thread.Start();
        MissionB_Thread.Start();
        NormalProcess();


    }
    //任務A
    private void MissionA()
    {
        for (int i = 0; i < 1000; i++)
        {
            if (i % 2 != 0)
            {
                Console.WriteLine("A" + i);
            }
        }
    }
    //任務B
    private void MissionB()
    {
        for (int i = 0; i < 1000; i++)
        {
            if (i % 2 == 0)
            {
                Console.WriteLine("B" + i);
            }
        }
    }
    //Normal
    private void NormalProcess()
    {
        Console.WriteLine("This is normal process ========================");
    }
}

ParameterizedThreadStart 執行緒

ParameterizedThreadStart 執行緒可以將參數值傳給委派物件

class Program
{
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.ReadKey();
    }
    //指派任務
    private void ProvideMission()
    {
        //指定委派物件
        ParameterizedThreadStart MissionA_Tg = new ParameterizedThreadStart(MissionA);
        //建立A任務執行緒
        Thread MissionA_Thread = new Thread(MissionA_Tg);
        MissionA_Thread.Name = "Mission A";

        //指定委派物件
        ParameterizedThreadStart MissionB_Tg = new ParameterizedThreadStart(MissionB);
        //建立B任務執行緒
        Thread MissionB_Thread = new Thread(MissionB_Tg);
        MissionB_Thread.Name = "Mission B";

        //啟動執行緒
        MissionA_Thread.Start(10);
        MissionB_Thread.Start(10);
        NormalProcess();


    }
    //任務A
    private void MissionA(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i % 2 != 0)
            {
                Console.WriteLine("A" + i);
                Thread.Sleep(1000);
            }
        }
    }
    //任務B
    private void MissionB(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i % 2 == 0)
            {
                Console.WriteLine("B" + i);
                Thread.Sleep(2000);
            }
        }
    }
    //Normal
    private void NormalProcess()
    {
        Console.WriteLine("This is normal process ========================");
    }
}

暫停 Thread.Sleep

在執行緒執行過程,可以透過Thread.Sleep讓執行緒暫停指定的毫秒

class Program
{
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.ReadKey();
    }
    //指派任務
    private void ProvideMission()
    {
        //指定委派物件
        ParameterizedThreadStart MissionA_Tg = new ParameterizedThreadStart(MissionA);
        //建立A任務執行緒
        Thread MissionA_Thread = new Thread(MissionA_Tg);
        MissionA_Thread.Name = "Mission A";

        //指定委派物件
        ParameterizedThreadStart MissionB_Tg = new ParameterizedThreadStart(MissionB);
        //建立B任務執行緒
        Thread MissionB_Thread = new Thread(MissionB_Tg);
        MissionB_Thread.Name = "Mission B";

        //啟動執行緒
        MissionA_Thread.Start(10);
        MissionB_Thread.Start(10);
        NormalProcess();


    }
    //任務A
    private void MissionA(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i % 2 != 0)
            {
                Console.WriteLine("A" + i);
                Thread.Sleep(1000);
            }
        }
    }
    //任務B
    private void MissionB(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i % 2 == 0)
            {
                Console.WriteLine("B" + i);
                Thread.Sleep(2000);
            }
        }
    }
    //Normal
    private void NormalProcess()
    {
        Console.WriteLine("This is normal process ========================");
    }
}

封鎖/阻塞 Thread.Join()

通常我們認知的Join是連結的意思,但是在C# Thread.Join 的意思是

可以封鎖指定的執行緒,直到執行緒執行完畢

主要用於控制順序,等封鎖的執行緒執行完畢,主處理序才會繼續往下走

class Program
{
    private Thread MissionA_Thread;
    private Thread MissionB_Thread;
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.WriteLine("Blocks the calling MissionA thread");
        mProgram.MissionA_Thread.Join();
        Console.WriteLine("MissionA thread terminates");
        Console.ReadKey();
    }
    //指派任務
    private void ProvideMission()
    {
        //指定委派物件
        ParameterizedThreadStart MissionA_Tg = new ParameterizedThreadStart(MissionA);
        //建立A任務執行緒
        MissionA_Thread = new Thread(MissionA_Tg);
        MissionA_Thread.Name = "Mission A";

        //指定委派物件
        ParameterizedThreadStart MissionB_Tg = new ParameterizedThreadStart(MissionB);
        //建立B任務執行緒
        MissionB_Thread = new Thread(MissionB_Tg);
        MissionB_Thread.Name = "Mission B";

        //啟動執行緒
        MissionA_Thread.Start(10);
        MissionB_Thread.Start(10);
        NormalProcess();


    }
    //任務A
    private void MissionA(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i % 2 != 0)
            {
                Console.WriteLine("A" + i);
                Thread.Sleep(1000);
            }
        }
    }
    //任務B
    private void MissionB(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i % 2 == 0)
            {
                Console.WriteLine("B" + i);
                Thread.Sleep(2000);
            }
        }
    }
    //Normal
    private void NormalProcess()
    {
        Console.WriteLine("This is normal process ========================");
    }
}

Lock 鎖定

Lock 可以針對委派至同一個物件時,控制鎖定資源

當多個執行緒執行同一物件,只要其中一個先執行,其他的就要排隊等他執行完

class Program
{
    private Thread MissionB_Thread;
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();
        Console.ReadKey();
    }
    //指派任務
    private void ProvideMission()
    {
        //指定委派物件
        ParameterizedThreadStart MissionA_Tg1 = new ParameterizedThreadStart(MissionA);
        ParameterizedThreadStart MissionA_Tg2 = new ParameterizedThreadStart(MissionA);
        ParameterizedThreadStart MissionA_Tg3 = new ParameterizedThreadStart(MissionA);
        //建立A任務執行緒
        Thread MissionA_Thread1 = new Thread(MissionA_Tg1);
        Thread MissionA_Thread2 = new Thread(MissionA_Tg2);
        Thread MissionA_Thread3 = new Thread(MissionA_Tg3);
        MissionA_Thread1.Name = "Mission A1";
        MissionA_Thread2.Name = "Mission A2";
        MissionA_Thread3.Name = "Mission A3";

        //指定委派物件
        ParameterizedThreadStart MissionB_Tg = new ParameterizedThreadStart(MissionB);
        //建立B任務執行緒
        MissionB_Thread = new Thread(MissionB_Tg);
        MissionB_Thread.Name = "Mission B";

        //啟動執行緒
        MissionA_Thread1.Start("Aa");
        MissionA_Thread2.Start("Aaa");
        MissionA_Thread3.Start("Aaaa");
        MissionB_Thread.Start(10);
        NormalProcess();


    }
    //任務A
    private void MissionA(object name)
    {
        string txt = Convert.ToString(name);
        for (int i = 0; i < 10; i++)
        {
            if (i % 2 != 0)
            {
                lock (this)
                {
                    Console.WriteLine(txt + i);
                    Thread.Sleep(1000);
                }
            }
        }
    }
    //任務B
    private void MissionB(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i % 2 == 0)
            {
                Console.WriteLine("B" + i);
                Thread.Sleep(2000);
            }
        }
    }
    //Normal
    private void NormalProcess()
    {
        Console.WriteLine("This is normal process ========================");
    }
}

Monitor 監控

Monitor 監控,提供更彈性的方式來控制執行緒流程

其中提供幾個靜態方法

Monitor.Enter : 開始監控 Monitor.Wait : 暫停執行緒 Monitor.Pluse : 喚醒被暫停的執行緒 Monitor.Exit : 結束監控

class Program
{
    private Thread MissionB_Thread;
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();

        Console.ReadKey();
    }
    //指派任務
    private void ProvideMission()
    {
        //指定委派物件
        ParameterizedThreadStart MissionA_Tg = new ParameterizedThreadStart(MissionA);
        //建立A任務執行緒
        Thread MissionA_Thread = new Thread(MissionA_Tg);
        MissionA_Thread.Name = "Mission A";


        //指定委派物件
        ParameterizedThreadStart MissionB_Tg = new ParameterizedThreadStart(MissionB);
        //建立B任務執行緒
        MissionB_Thread = new Thread(MissionB_Tg);
        MissionB_Thread.Name = "Mission B";

        //啟動執行緒
        MissionA_Thread.Start(10);
        MissionB_Thread.Start(10);

        //暫停主執行緒
        MissionB_Thread.Join();

        NormalProcess();

        //開始監控
        Monitor.Enter(this);
        //喚醒被暫停的執行緒
        Monitor.Pulse(this);
        //結束監控
        Monitor.Exit(this);
    }
    //任務A
    private void MissionA(object value)
    {
        //開始監控
        Monitor.Enter(this);

        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            if (i == 5)
            {
                //暫停執行緒
                Monitor.Wait(this);
                
            }
            Console.WriteLine("A" + i);
            Thread.Sleep(1000);
        }

        //結束監控
        Monitor.Exit(this);
    }
    //任務B
    private void MissionB(object value)
    {
        int num = Convert.ToInt32(value);
        for (int i = 0; i < num; i++)
        {
            Console.WriteLine("B" + i);
            Thread.Sleep(2000);
        }
    }
    //Normal
    private void NormalProcess()
    {
        Console.WriteLine("This is normal process ========================");
    }
}

Interrupt 中斷執行緒

在執行緒運作時,可以透過 Interrupt 阻斷執行緒

並且可以透過 try catch 捕捉例外

當指定執行緒被終止時,Join也會立即執行完畢

class Program
{
    private Thread MissionA_Thread;
    private Thread MissionB_Thread;
    static void Main(string[] args)
    {
        Program mProgram = new Program();
        mProgram.ProvideMission();

        Console.ReadKey();
    }
    //指派任務
    private void ProvideMission()
    {
        //指定委派物件
        ParameterizedThreadStart MissionA_Tg = new ParameterizedThreadStart(MissionA);
        //建立A任務執行緒
        MissionA_Thread = new Thread(MissionA_Tg);
        MissionA_Thread.Name = "Mission A";


        //指定委派物件
        ParameterizedThreadStart MissionB_Tg = new ParameterizedThreadStart(MissionB);
        //建立B任務執行緒
        MissionB_Thread = new Thread(MissionB_Tg);
        MissionB_Thread.Name = "Mission B";

        //啟動執行緒
        MissionA_Thread.Start(10);
        MissionB_Thread.Start(10);

        //暫停主執行緒
        MissionB_Thread.Join();

        NormalProcess();

    }
    //任務A
    private void MissionA(object value)
    {
        try
        {
            int num = Convert.ToInt32(value);
            for (int i = 0; i < num; i++)
            {
                if (i == 5)
                {
                    //中斷執行緒
                    MissionA_Thread.Interrupt();
                }
                Console.WriteLine("A" + i);
                Thread.Sleep(1000);
            }
        }catch (ThreadInterruptedException)
        {
            //
            Console.WriteLine(Thread.CurrentThread.Name);
        }
    }
    //任務B
    private void MissionB(object value)
    {
        try { 
            int num = Convert.ToInt32(value);
            for (int i = 0; i < num; i++)
            {
                if (i > 6)
                {
                    //中斷執行緒
                    MissionB_Thread.Interrupt();
                }
                Console.WriteLine("B" + i);
                Thread.Sleep(2000);
            }
        }
        catch (ThreadInterruptedException)
        {
            //捕捉中斷執行緒拋出的例外
            Console.WriteLine(Thread.CurrentThread.Name+"Is Stop");
        }
    }
    //Normal
    private void NormalProcess()
    {
        Console.WriteLine("This is normal process ========================");
    }
}

Abort 手動終止執行緒

在執行緒啟動過程,可以透過 Abort 強制停止

if(MissionA_Thread.IsAlve)
{
    MissionA_Thread.Abort();
}

IsBackground 背景執行

在多數執行緒設計,都會需要持續執行、並且在主要程式結束時跟著停止

這時只要將 IsBackground 設定為 true 就可以達到背景執行,程式結束就跟著結束

//指定委派物件
ParameterizedThreadStart MissionA_Tg = new ParameterizedThreadStart(MissionA);
//建立A任務執行緒
MissionA_Thread = new Thread(MissionA_Tg);
//設定為背景執行
MissionA_Thread.IsBackground = true;

MissionA_Thread.Start();