C#的多線程機(jī)制探索(續(xù)3)
發(fā)表時(shí)間:2024-02-22 來(lái)源:明輝站整理相關(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ì)象來(lái)同步四個(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è)置為無(wú)信號(hào)狀態(tài)。這里用它的有信號(hào)狀態(tài)來(lá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 gM1 = new Mutex(true,"MyMutex"); //創(chuàng)建一個(gè)未命名的Mutex 對(duì)象. gM2 = new Mutex(true); Console.WriteLine(" - Main Owns gM1 and gM2");
AutoResetEvent[] evs = new AutoResetEvent[4]; evs[0] = Event1; file://為后面的線程t1,t2,t3,t4定義AutoResetEvent對(duì)象 evs[1] = Event2; evs[2] = Event3; evs[3] = Event4;
MutexSample tm = new MutexSample( ); Thread t1 = new Thread(new ThreadStart(tm.t1Start)); Thread t2 = new Thread(new ThreadStart(tm.t2Start)); Thread t3 = new Thread(new ThreadStart(tm.t3Start)); Thread t4 = new Thread(new ThreadStart(tm.t4Start)); t1.Start( );// 使用Mutex.WaitAll()方法等待一個(gè)Mutex數(shù)組中的對(duì)象全部被釋放 t2.Start( );// 使用Mutex.WaitOne()方法等待gM1的釋放 t3.Start( );// 使用Mutex.WaitAny()方法等待一個(gè)Mutex數(shù)組中任意一個(gè)對(duì)象被釋放 t4.Start( );// 使用Mutex.WaitOne()方法等待gM2的釋放
Thread.Sleep(2000); Console.WriteLine(" - Main releases gM1"); gM1.ReleaseMutex( ); file://線程t2,t3結(jié)束條件滿足
Thread.Sleep(1000); Console.WriteLine(" - Main releases gM2"); gM2.ReleaseMutex( ); file://線程t1,t4結(jié)束條件滿足
//等待所有四個(gè)線程結(jié)束 WaitHandle.WaitAll(evs); Console.WriteLine("... Mutex Sample"); Console.ReadLine(); }
public void t1Start( ) { Console.WriteLine("t1Start started, Mutex.WaitAll(Mutex[])"); Mutex[] gMs = new Mutex[2]; gMs[0] = gM1;//創(chuàng)建一個(gè)Mutex數(shù)組作為Mutex.WaitAll()方法的參數(shù) gMs[1] = gM2; Mutex.WaitAll(gMs);//等待gM1和gM2都被釋放 Thread.Sleep(2000); Console.WriteLine("t1Start finished, Mutex.WaitAll(Mutex[]) satisfied"); Event1.Set( ); file://線程結(jié)束,將Event1設(shè)置為有信號(hào)狀態(tài) }
public void t2Start( ) { Console.WriteLine("t2Start started, gM1.WaitOne( )"); gM1.WaitOne( );//等待gM1的釋放 Console.WriteLine("t2Start finished, gM1.WaitOne( ) satisfied"); Event2.Set( );//線程結(jié)束,將Event2設(shè)置為有信號(hào)狀態(tài) }
public void t3Start( ) { Console.WriteLine("t3Start started, Mutex.WaitAny(Mutex[])"); Mutex[] gMs = new Mutex[2]; gMs[0] = gM1;//創(chuàng)建一個(gè)Mutex數(shù)組作為Mutex.WaitAny()方法的參數(shù) gMs[1] = gM2; Mutex.WaitAny(gMs);//等待數(shù)組中任意一個(gè)Mutex對(duì)象被釋放 Console.WriteLine("t3Start finished, Mutex.WaitAny(Mutex[])"); Event3.Set( );//線程結(jié)束,將Event3設(shè)置為有信號(hào)狀態(tài) }
public void t4Start( ) { Console.WriteLine("t4Start started, gM2.WaitOne( )"); gM2.WaitOne( );//等待gM2被釋放 Console.WriteLine("t4Start finished, gM2.WaitOne( )"); Event4.Set( );//線程結(jié)束,將Event4設(shè)置為有信號(hào)狀態(tài) } }
|