關於AutoResetEvent和ManualResetEvent 全面總結

兩者都繼承自EventWaitHandle,自然也就有點相通的地方了

簡單來說,無論是AutoResetEvent還是ManualResetEvent,都是通過發出Signal信號來通知正在等待的線程的。

有人可能要問,爲什麼要用它們來做這些事情,

嗯, 是這樣的, 在.Net的多線程環境中,資源的共享變得尤其重要,如果沒有一個有效的方法來維護資源的原子狀態,在搶佔式的CPU環境中,所有的事情都會變得無法控制。AutoResetEvent和ManualResetEvent正是用來保證資源的原子性的一個手段的兩個方面。

正如它們的名字一樣, AutoResetEvent會在每次被Signal了之後自動(Automatically)轉變爲UnSignal,而ManualResetEvent則不然,無論是Signal還是UnSignal都需要人爲的介入去改變它的狀態。

在AutoResetEvent的構造函數中,有唯一的一個參數,initialState,Boolean類型,它用來初始化AutoResetEvent的Signal狀態,True爲Signal,False爲UnSignal,這與ManualResetEvent的構造函數是一樣的。

AutoResetEvent或ManualResetEvent都是通過Set()/Reset()兩個方法來Signal/UnSignal信號,通過調用WaitOne方法來阻塞當前線程,當收到Signal後就繼續往下執行。上面提到過,AutoResetEvent會自動把信號復位(自動調用Reset),而ManualResetEvent則需要人手復位,也就是說,AutoResetEvent每次只允許一條線程進入,其它所有需要訪問該資源的線程都要排隊等候,直到AutoResetEvent得到信號後,下一條線程開始工作,同時AutoResetEvent又會自動復位信號,讓其他線程繼續等候;而ManualResetEvent則每次可以喚醒多個線程,因爲當ManualResetEvent得到信號後,其他調用WaitOne方法的線程都將得到信號得以繼續往下執行,ManualResetEvent不會自動復位信號,換句話說,除非手動的調用了ManualResetEvent.Reset方法,否則ManualResetEvent一直保持有信號狀態,這樣就可以同時喚醒多條線程了

 

public partial class Form1 : Form
    {
        protected AutoResetEvent autoEvent;
         protected ManualResetEvent manualEvent;
 
         public Form1()
         {
             InitializeComponent();
 
            autoEvent = new AutoResetEvent(true);
            manualEvent = new ManualResetEvent(false);

            Thread aThread = new Thread(new ParameterizedThreadStart(Foo));
            aThread.Name = "aThread";
            aThread.IsBackground = true;
            aThread.Start();
        }

        private void Foo(object state)
        {
            MessageBox.Show("1");
            autoEvent.WaitOne();
           // manualEvent.WaitOne();
            MessageBox.Show("2");
            autoEvent.WaitOne();
          //  manualEvent.WaitOne();
            MessageBox.Show("3");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            autoEvent.Set();
           // manualEvent.Set();
        }

作爲一個示例,下面的DemoCode一開始就運行一條子線程,然後用AutoResetEvent/ManualResetEvent來控制MessageBox的輸出流程。

如果在Foo和button1_Click裏面用AutoResetEvent,一開始得到"1",然後每點擊一次Button1得到"2"和"3"。

如果用ManualResetEvent,一開始得到"1",然後只需點擊Button1一次,就可以得到"2"和"3"了

 

總結:

在C#多線程編程中,這兩個類幾乎是不可或缺的,他們的用法/聲明都很類似,那麼區別在哪裏了

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也就可以同時喚醒多個線程繼續執行

 

這些內容是基於網絡的各位前輩的內容能總結而成!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章