C#的多線程機(jī)制探索(續(xù)3)
發(fā)表時(shí)間:2024-02-22 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]五、互斥對(duì)象——更加靈活的同步方式有時(shí)候你會(huì)覺得上面介紹的方法好像不夠用,對(duì),我們解決了代碼和資源的同步問題,解決了多線程自動(dòng)化管理和定時(shí)觸發(fā)的問題,但是如何控制多個(gè)線程相互之間的聯(lián)系呢?例如我要到餐廳吃飯,在吃飯之前我先得等待廚師把飯菜做好,之后我開始吃飯,吃完我還得付款,付款方式可以是現(xiàn)金...
五、互斥對(duì)象——更加靈活的同步方式
有時(shí)候你會(huì)覺得上面介紹的方法好像不夠用,對(duì),我們解決了代碼和資源的同步問題,解決了多線程自動(dòng)化管理和定時(shí)觸發(fā)的問題,但是如何控制多個(gè)線程相互之間的聯(lián)系呢?例如我要到餐廳吃飯,在吃飯之前我先得等待廚師把飯菜做好,之后我開始吃飯,吃完我還得付款,付款方式可以是現(xiàn)金,也可以是信用卡,付款之后我才能離開。分析一下這個(gè)過程,我吃飯可以看作是主線程,廚師做飯又是一個(gè)線程,服務(wù)員用信用卡收款和收現(xiàn)金可以看作另外兩個(gè)線程,大家可以很清楚地看到其中的關(guān)系——我吃飯必須等待廚師做飯,然后等待兩個(gè)收款線程之中任意一個(gè)的完成,然后我吃飯這個(gè)線程可以執(zhí)行離開這個(gè)步驟,于是我吃飯才算結(jié)束了。事實(shí)上,現(xiàn)實(shí)中有著比這更復(fù)雜的聯(lián)系,我們?cè)鯓硬拍芎芎玫乜刂扑鼈兌划a(chǎn)生沖突和重復(fù)呢?
這種情況下,我們需要用到互斥對(duì)象,即System.Threading命名空間中的Mutex類。大家一定坐過出租車吧,事實(shí)上我們可以把Mutex看作一個(gè)出租車,那么乘客就是線程了,乘客首先得等車,然后上車,最后下車,當(dāng)一個(gè)乘客在車上時(shí),其他乘客就只有等他下車以后才可以上車。而線程與Mutex對(duì)象的關(guān)系也正是如此,線程使用Mutex.WaitOne()方法等待Mutex對(duì)象被釋放,如果它等待的Mutex對(duì)象被釋放了,它就自動(dòng)擁有這個(gè)對(duì)象,直到它調(diào)用Mutex.ReleaseMutex()方法釋放這個(gè)對(duì)象,而在此期間,其他想要獲取這個(gè)Mutex對(duì)象的線程都只有等待。
下面這個(gè)例子使用了Mutex對(duì)象來同步四個(gè)線程,主線程等待四個(gè)線程的結(jié)束,而這四個(gè)線程的運(yùn)行又是與兩個(gè)Mutex對(duì)象相關(guān)聯(lián)的。其中還用到AutoResetEvent類的對(duì)象,如同上面提到的ManualResetEvent對(duì)象一樣,大家可以把它簡(jiǎn)單地理解為一個(gè)信號(hào)燈,使用AutoResetEvent.Set()方法可以設(shè)置它為有信號(hào)狀態(tài),而使用AutoResetEvent.Reset()方法把它設(shè)置為無信號(hào)狀態(tài)。這里用它的有信號(hào)狀態(tài)來表示一個(gè)線程的結(jié)束。
// Mutex.cs using System; using System.Threading;
public class MutexSample { static Mutex gM1; static Mutex gM2; const int ITERS = 100; static AutoResetEvent Event1 = new AutoResetEvent(false); static AutoResetEvent Event2 = new AutoResetEvent(false); static AutoResetEvent Event3 = new AutoResetEvent(false); static AutoResetEvent Event4 = new AutoResetEvent(false);
public static void Main(String[] args) { Console.WriteLine("Mutex Sample ..."); 。牐//創(chuàng)建一個(gè)Mutex對(duì)象,并且命名為MyMutex 。牐爂M1 = new Mutex(true,"MyMutex"); //創(chuàng)建一個(gè)未命名的Mutex 對(duì)象. 。牐爂M2 = new Mutex(true); Console.WriteLine(" - Main Owns gM1 and gM2");
。牐燗utoResetEvent[] evs = new AutoResetEvent[4]; evs[0] = Event1; file://為后面的線程t1,t2,t3,t4定義AutoResetEvent對(duì)象 。牐爀vs[1] = Event2; 。牐爀vs[2] = Event3; 。牐爀vs[3] = Event4;
。牐燤utexSample tm = new MutexSample( ); 。牐燭hread t1 = new Thread(new ThreadStart(tm.t1Start)); 。牐燭hread t2 = new Thread(new ThreadStart(tm.t2Start)); 。牐燭hread t3 = new Thread(new ThreadStart(tm.t3Start)); 。牐燭hread t4 = new Thread(new ThreadStart(tm.t4Start)); t1.Start( );// 使用Mutex.WaitAll()方法等待一個(gè)Mutex數(shù)組中的對(duì)象全部被釋放 。牐爐2.Start( );// 使用Mutex.WaitOne()方法等待gM1的釋放 。牐爐3.Start( );// 使用Mutex.WaitAny()方法等待一個(gè)Mutex數(shù)組中任意一個(gè)對(duì)象被釋放 t4.Start( );// 使用Mutex.WaitOne()方法等待gM2的釋放
。牐燭hread.Sleep(2000); Console.WriteLine(" - Main releases gM1"); 。牐爂M1.ReleaseMutex( ); file://線程t2,t3結(jié)束條件滿足
。牐燭hread.Sleep(1000); 。牐燙onsole.WriteLine(" - Main releases gM2"); 。牐爂M2.ReleaseMutex( ); file://線程t1,t4結(jié)束條件滿足
//等待所有四個(gè)線程結(jié)束 。牐燱aitHandle.WaitAll(evs); Console.WriteLine("... Mutex Sample"); 。牐燙onsole.ReadLine(); }
public void t1Start( ) { Console.WriteLine("t1Start started, Mutex.WaitAll(Mutex[])"); 。牐燤utex[] gMs = new Mutex[2]; 。牐爂Ms[0] = gM1;//創(chuàng)建一個(gè)Mutex數(shù)組作為Mutex.WaitAll()方法的參數(shù) 。牐爂Ms[1] = gM2; 。牐燤utex.WaitAll(gMs);//等待gM1和gM2都被釋放 Thread.Sleep(2000); 。牐燙onsole.WriteLine("t1Start finished, Mutex.WaitAll(Mutex[]) satisfied"); Event1.Set( ); file://線程結(jié)束,將Event1設(shè)置為有信號(hào)狀態(tài) }
public void t2Start( ) { 。牐燙onsole.WriteLine("t2Start started, gM1.WaitOne( )"); gM1.WaitOne( );//等待gM1的釋放 。牐燙onsole.WriteLine("t2Start finished, gM1.WaitOne( ) satisfied"); 。牐燛vent2.Set( );//線程結(jié)束,將Event2設(shè)置為有信號(hào)狀態(tài) }
public void t3Start( ) { 。牐燙onsole.WriteLine("t3Start started, Mutex.WaitAny(Mutex[])"); Mutex[] gMs = new Mutex[2]; 。牐爂Ms[0] = gM1;//創(chuàng)建一個(gè)Mutex數(shù)組作為Mutex.WaitAny()方法的參數(shù) gMs[1] = gM2; 。牐燤utex.WaitAny(gMs);//等待數(shù)組中任意一個(gè)Mutex對(duì)象被釋放 。牐燙onsole.WriteLine("t3Start finished, Mutex.WaitAny(Mutex[])"); 。牐燛vent3.Set( );//線程結(jié)束,將Event3設(shè)置為有信號(hào)狀態(tài) }
public void t4Start( ) { 。牐燙onsole.WriteLine("t4Start started, gM2.WaitOne( )"); 。牐爂M2.WaitOne( );//等待gM2被釋放 Console.WriteLine("t4Start finished, gM2.WaitOne( )"); 。牐燛vent4.Set( );//線程結(jié)束,將Event4設(shè)置為有信號(hào)狀態(tài) } }
|