1. 程式人生 > 其它 >C#執行緒開始/暫停/終止

C#執行緒開始/暫停/終止

參考:https://www.cnblogs.com/haoyun99/archive/2012/08/22/2651537.html

很好用

寫測試工具需要多執行緒的暫停終止。用C#的 Thread.about() join() resume() suspend()又提示函式過時了,不建議使用。於是四處找方法,訊號量、互斥鎖什麼的方法也不少,找到下面這個方法,倒是很實用,轉載如下:

C#關於AutoResetEvent的使用介紹(轉)

AutoResetEvent允許執行緒通過發訊號互相通訊。通常,此通訊涉及執行緒需要獨佔訪問的資源。

執行緒通過呼叫AutoResetEvent上的WaitOne來等待訊號。如果AutoResetEvent

處於非終止狀態,則該執行緒阻塞,並等待當前控制資源的執行緒
通過呼叫Set發出資源可用的訊號。

呼叫SetAutoResetEvent發訊號以釋放等待執行緒。AutoResetEvent將保持終止狀態,直到一個正在等待的執行緒被釋放,然後自動返回非終止狀態。如果沒有任何執行緒在等待,則狀態將無限期地保持為終止狀態。

可以通過將一個布林值傳遞給建構函式來控制AutoResetEvent的初始狀態,如果初始狀態為終止狀態,則為true;否則為false

通俗的來講只有等myResetEven.Set()成功執行後,myResetEven.WaitOne()才能夠獲得執行機會;Set是發訊號,WaitOne是等待訊號,只有發了訊號,
等待的才會執行。如果不發的話,WaitOne後面的程式就永遠不會執行。下面我們來舉一個例子:我去書店買書,當我選中一本書後我會去收費處付錢,
付好錢後再去倉庫取書。這個順序不能顛倒,我作為主執行緒,收費處和倉庫做兩個輔助執行緒,程式碼如下:

using System;
using System.Linq;
using System.Activities;
using System.Activities.Statements;
using System.Threading;

namespace CaryAREDemo
{
    class Me
    {
        const int numIterations = 550;
        static AutoResetEvent myResetEvent = new AutoResetEvent(false);
        static AutoResetEvent ChangeEvent = new AutoResetEvent(false);
        //static ManualResetEvent myResetEvent = new ManualResetEvent(false);
        //static ManualResetEvent ChangeEvent = new ManualResetEvent(false);
        static int number; //這是關鍵資源

        static void Main()
        {
            Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc));
            payMoneyThread.Name = "付錢執行緒";
            Thread getBookThread = new Thread(new ThreadStart(GetBookProc));
            getBookThread.Name = "取書執行緒";
            payMoneyThread.Start();
            getBookThread.Start();

            for (int i = 1; i <= numIterations; i++)
            {
                Console.WriteLine("買書執行緒:數量{0}", i);
                number = i;
                //Signal that a value has been written.
                myResetEvent.Set();
                ChangeEvent.Set();
                Thread.Sleep(0);
            }
            payMoneyThread.Abort();
            getBookThread.Abort();
        }

        static void PayMoneyProc()
        {
            while (true)
            {
                myResetEvent.WaitOne();
                //myResetEvent.Reset();
                Console.WriteLine("{0}:數量{1}", Thread.CurrentThread.Name, number);
            }
        }
        static void GetBookProc()
        {
            while (true)
            {
                ChangeEvent.WaitOne();
                // ChangeEvent.Reset();               
                Console.WriteLine("{0}:數量{1}", Thread.CurrentThread.Name, number);
                Console.WriteLine("------------------------------------------");
                Thread.Sleep(0);
            }
        }
    }
}
執行結果如下:

AutoResetEvent與ManualResetEvent的區別

他們的用法\宣告都很類似,Set方法將訊號置為傳送狀態 Reset方法將訊號置為不傳送狀態WaitOne等待訊號的傳送。其實,從名字就可以看出一個手動,
一個自動,這個手動和自動實際指的是在Reset方法的處理上,如下面例子:

public AutoResetEvent autoevent=new AutoResetEvent(true);
public ManualResetEvent manualevent=new ManualResetEvent(true);

預設訊號都處於傳送狀態,

autoevent.WaitOne();
manualevent.WaitOne();

如果 某個執行緒呼叫上面該方法,則當訊號處於傳送狀態時,該執行緒會得到訊號,得以繼續執行。差別就在呼叫後,autoevent.WaitOne()每次只允許一個執行緒
進入,當某個執行緒得到訊號(也就是有其他執行緒呼叫了autoevent.Set()方法後)後,autoevent會自動又將訊號置為不傳送狀態,則其他呼叫WaitOne的執行緒只
有繼續等待.也就是說,autoevent一次只喚醒一個執行緒。而manualevent則可以喚醒多個執行緒,因為當某個執行緒呼叫了set方法後,其他呼叫waitone的執行緒
獲得訊號得以繼續執行,而manualevent不會自動將訊號置為不傳送.也就是說,除非手工呼叫了manualevent.Reset().方法,則 manualevent將一直保持有訊號狀態,manualevent也就可以同時喚醒多個執行緒繼續執行。如果上面的程式換成 ManualResetEvent的話,就需要在waitone後面做下reset。