明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

C#的多線程機(jī)制探索(續(xù)3)

[摘要]五、互斥對(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)
  }
}