標籤:
一:終止狀態和非終止狀態 首先說說線程的終止狀態和非終止狀態。AutoResetEvent和ManualResetEvent的建構函式中,都有bool變數來指明線程的終止狀態和非終止狀態。true表示終止狀態(個人理解也就是可運行狀態,根據理解應該是該線程的阻塞終止了),false表示非終止狀態。
AutoResetEvent _autoResetEvent = new AutoResetEvent(false); private void BT_Temp_Click(object sender, RoutedEventArgs e) { Thread t1 = new Thread(this.Thread1Foo); t1.Start(); Thread.Sleep(3000); //Thread.Sleep(Int32)是批當前進程掛起3000毫秒,與線程t1是一點關係也沒有的。 _autoResetEvent.Set(); } void Thread1Foo() { _autoResetEvent.WaitOne(); MessageBox.Show("t1 end"); } 這段代碼的執行結果,就是3秒鐘過後,彈出“t1 end”。 而如果把: AutoResetEvent _autoResetEvent = new AutoResetEvent(false); 改為: AutoResetEvent _autoResetEvent = new AutoResetEvent(true); 則“t1 end”將會立刻彈出。 也就是說,在終止狀態中,_autoResetEvent.WaitOne()是不會起到阻滯背景工作執行緒的作用的。(PS:ManualResetEvent也同樣)二:AutoResetEvent和ManualResetEvent的區別
AutoResetEvent 允許線程通過發訊號互相通訊。 通常,當線程需要獨佔訪問資源時使用該類。
線程通過調用 AutoResetEvent 上的 WaitOne 來等待訊號。 如果 AutoResetEvent 為非終止狀態,則線程會被阻止,並等待當前控制資源的線程通過調用 Set來通知資源可用。
調用 Set 向 AutoResetEvent 發訊號以釋放等待線程。 AutoResetEvent 將保持終止狀態,直到一個正在等待的線程被釋放,然後自動返回非終止狀態。 如果沒有任何線程在等待,則狀態將無限期地保持 為終止狀態。如果當 AutoResetEvent 為終止狀態時線程調用 WaitOne,則線程不會被阻止。 AutoResetEvent 將立即釋放線程並返回到非終止狀態。
AutoResetEvent _autoResetEvent = new AutoResetEvent(false); private void BT_Temp_Click(object sender, RoutedEventArgs e) { Thread t1 = new Thread(this.Thread1Foo); t1.Start(); Thread t2 = new Thread(this.Thread2Foo); t2.Start(); Thread.Sleep(3000); _autoResetEvent.Set(); } void Thread1Foo() { _autoResetEvent.WaitOne(); MessageBox.Show("t1 end"); } void Thread2Foo() { _autoResetEvent.WaitOne(); MessageBox.Show("t2 end"); } 該段代碼啟動並執行效果是,過3秒後,要麼彈出“t1 end”,要麼彈出“t2 end”,不會兩個都彈出。也就是說,其中一個進行將會結束,而另一個進程永遠不會結束。程式碼片段3: ManualResetEvent _menuRestEvent = new ManualResetEvent(false); private void BT_Temp_Click(object sender, RoutedEventArgs e) { Thread t1 = new Thread(this.Thread1Foo); t1.Start(); Thread t2 = new Thread(this.Thread2Foo); t2.Start(); Thread.Sleep(3000); _menuRestEvent.Set(); } void Thread1Foo() { _menuRestEvent.WaitOne(); MessageBox.Show("t1 end"); } void Thread2Foo() { _menuRestEvent.WaitOne(); MessageBox.Show("t2 end"); } 該段代碼啟動並執行效果是,過3秒後,“t1 end”和“t2 end”,兩個都被彈出。也就是說,兩個進程都結束了。 這個特性就是說,AutoResetEvent只會給一個線程發送訊號,而不會給多個線程發送訊號。在我們需要同步多個線程的時候,就只能採用ManualResetEvent了。至於深層次的原因是,AutoResetEvent在set()之後,會將線程 狀態自動置為false,而ManualResetEvent在Set()後,線程的狀態就變為true了,必須手動ReSet()之後,才會重新將線程置為false。這也就是為什麼他們的名字一個為Auto,一個為Manual的原因。為了更加充分的驗證Manua lResetEvent的這點特性,我們再來看程式碼片段4程式碼片段4: ManualResetEvent _menuRestEvent = new ManualResetEvent(false); private void BT_Temp_Click(object sender, RoutedEventArgs e) { Thread t1 = new Thread(this.Thread1Foo); t1.Start(); Thread t2 = new Thread(this.Thread2Foo); t2.Start(); Thread.Sleep(3000); _menuRestEvent.Set(); //_menuRestEvent.Reset(); } void Thread1Foo() { _menuRestEvent.WaitOne(); MessageBox.Show("t1 step1 end"); //睡1S,用於等待主線程_menuRestEvent.Reset(); Thread.Sleep(1000); _menuRestEvent.WaitOne(); MessageBox.Show("t1 step2 end"); } void Thread2Foo() { _menuRestEvent.WaitOne(); MessageBox.Show("t2 step1 end"); //睡1S,用於等待主線程_menuRestEvent.Reset(); Thread.Sleep(1000); _menuRestEvent.WaitOne(); MessageBox.Show("t2 step2 end"); } 在程式碼片段4中,我們對//_menuRestEvent.Reset()進行了注釋,也就是說, _menuRestEvent.Set()後,線程的狀態就是true狀態的,程式啟動並執行結果是"t1 step1 end"、"t1 step2 end"、"t1 step2 end"、"t2 step2 end"在3秒之後全部彈出。 而如果我們將//_menuRestEvent.Reset()的注釋去掉,會發現"t1 step2 end"和"t2 step2 end"永遠不會彈出。除非我們在主線程中再次對_menuRestEvent進行Set()。
C#AutoResetEvent和ManualResetEvent的區別