亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

C#多線程學習之(三)生產者和消費者用法分析

2020-01-24 02:01:47
字體:
來源:轉載
供稿:網友

本文實例講述了C#多線程學習之生產者和消費者用法。分享給大家供大家參考。具體實分析如下:

前面的文章說過,每個線程都有自己的資源,但是代碼區是共享的,即每個線程都可以執行相同的函數。這可能帶來的問題就是幾個線程同時執行一個函數,導致數據的混亂,產生不可預料的結果,因此我們必須避免這種情況的發生。

C#提供了一個關鍵字lock,它可以把一段代碼定義為互斥段(critical section),互斥段在一個時刻內只允許一個線程進入執行,而其他線程必須等待。在C#中,關鍵字lock定義如下:

lock(expression) statement_block 

expression代表你希望跟蹤的對象,通常是對象引用。
如果你想保護一個類的實例,一般地,你可以使用this;
如果你想保護一個靜態變量(如互斥代碼段在一個靜態方法內部),一般使用類名就可以了。

而statement_block就是互斥段的代碼,這段代碼在一個時刻內只可能被一個線程執行。

下面是一個使用lock關鍵字的典型例子,在注釋里說明了lock關鍵字的用法和用途。
示例如下:

using System;using System.Threading;namespace ThreadSimple{ internal class Account  {  int balance;  Random r = new Random();  internal Account(int initial)   {   balance = initial;  }   internal int Withdraw(int amount)   {   if (balance < 0)   {    //如果balance小于0則拋出異常    throw new Exception("Negative Balance");   }   //下面的代碼保證在當前線程修改balance的值完成之前   //不會有其他線程也執行這段代碼來修改balance的值   //因此,balance的值是不可能小于0 的   lock (this)   {    Console.WriteLine("Current Thread:"+Thread.CurrentThread.Name);    //如果沒有lock關鍵字的保護,那么可能在執行完if的條件判斷之后    //另外一個線程卻執行了balance=balance-amount修改了balance的值    //而這個修改對這個線程是不可見的,所以可能導致這時if的條件已經不成立了    //但是,這個線程卻繼續執行balance=balance-amount,所以導致balance可能小于0    if (balance >= amount)     {     Thread.Sleep(5);     balance = balance - amount;     return amount;    }     else     {     return 0; // transaction rejected     }   }  }  internal void DoTransactions()   {   for (int i = 0; i < 100; i++)    Withdraw(r.Next(-50, 100));  } }  internal class Test  {  static internal Thread[] threads = new Thread[10];  public static void Main()   {   Account acc = new Account (0);   for (int i = 0; i < 10; i++)    {    Thread t = new Thread(new ThreadStart(acc.DoTransactions));    threads[i] = t;   }   for (int i = 0; i < 10; i++)     threads[i].Name=i.ToString();   for (int i = 0; i < 10; i++)     threads[i].Start();   Console.ReadLine();  } }}

Monitor 類鎖定一個對象

當多線程公用一個對象時,也會出現和公用代碼類似的問題,這種問題就不應該使用lock關鍵字了,這里需要用到System.Threading中的一個類Monitor,我們可以稱之為監視器,Monitor提供了使線程共享資源的方案。

Monitor類可以鎖定一個對象,一個線程只有得到這把鎖才可以對該對象進行操作。對象鎖機制保證了在可能引起混亂的情況下一個時刻只有一個線程可以訪問這個對象。
Monitor必須和一個具體的對象相關聯,但是由于它是一個靜態的類,所以不能使用它來定義對象,而且它的所有方法都是靜態的,不能使用對象來引用。下面代碼說明了使用Monitor鎖定一個對象的情形:

......Queue oQueue=new Queue();......Monitor.Enter(oQueue);......//現在oQueue對象只能被當前線程操縱了Monitor.Exit(oQueue);//釋放鎖

如上所示,當一個線程調用Monitor.Enter()方法鎖定一個對象時,這個對象就歸它所有了, 其它線程想要訪問這個對象,只有等待它使用Monitor.Exit()方法釋放鎖。為了保證線程最終都能釋放鎖,你可以把Monitor.Exit() 方法寫在try-catch-finally結構中的finally代碼塊里。

對于任何一個被Monitor鎖定的對象,內存中都保存著與它相關的一些信息:
其一是現在持有鎖的線程的引用;
其二是一個預備隊列,隊列中保存了已經準備好獲取鎖的線程;
其三是一個等待隊列,隊列中保存著當前正在等待這個對象狀態改變的隊列的引用。

當擁有對象鎖的線程準備釋放鎖時,它使用Monitor.Pulse()方法通知等待隊列中的第一個線程,于是該線程被轉移到預備隊列中,當對象鎖被釋放時,在預備隊列中的線程可以立即獲得對象鎖。

下面是一個展示如何使用lock關鍵字和Monitor類來實現線程的同步和通訊的例子,也是一個典型的生產者與消費者問題。
這個例程中,生產者線程和消費者線程是交替進行的,生產者寫入一個數,消費者立即讀取并且顯示(注釋中介紹了該程序的精要所在)。

用到的系統命名空間如下:

using System;using System.Threading;

首先,定義一個被操作的對象的類Cell,在這個類里,有兩個方法:ReadFromCell()和 WriteToCell。消費者線程將調用ReadFromCell()讀取cellContents的內容并且顯示出來,生產者進程將調用 WriteToCell()方法向cellContents寫入數據。

示例如下:

public class Cell{  int cellContents; // Cell對象里邊的內容  bool readerFlag = false; // 狀態標志,為true時可以讀取,為false則正在寫入  public int ReadFromCell( )  {   lock(this) // Lock關鍵字保證了什么,請大家看前面對lock的介紹   {    if (!readerFlag)//如果現在不可讀取    {      try     {      //等待WriteToCell方法中調用Monitor.Pulse()方法      Monitor.Wait(this);     }     catch (SynchronizationLockException e)     {      Console.WriteLine(e);     }     catch (ThreadInterruptedException e)     {      Console.WriteLine(e);     }    }    Console.WriteLine("Consume: {0}",cellContents);    readerFlag = false;    //重置readerFlag標志,表示消費行為已經完成    Monitor.Pulse(this);     //通知WriteToCell()方法(該方法在另外一個線程中執行,等待中)   }   return cellContents;  }  public void WriteToCell(int n)  {   lock(this)   {    if (readerFlag)    {     try     {      Monitor.Wait(this);     }     catch (SynchronizationLockException e)     {      //當同步方法(指Monitor類除Enter之外的方法)在非同步的代碼區被調用      Console.WriteLine(e);     }     catch (ThreadInterruptedException e)     {       //當線程在等待狀態的時候中止       Console.WriteLine(e);     }    }    cellContents = n;    Console.WriteLine("Produce: {0}",cellContents);    readerFlag = true;     Monitor.Pulse(this);     //通知另外一個線程中正在等待的ReadFromCell()方法   }  }}

下面定義生產者類 CellProd 和消費者類 CellCons ,它們都只有一個方法ThreadRun(),以便在Main()函數中提供給線程的ThreadStart代理對象,作為線程的入口。

public class CellProd{ Cell cell; // 被操作的Cell對象 int quantity = 1; // 生產者生產次數,初始化為1  public CellProd(Cell box, int request) {  //構造函數  cell = box;   quantity = request;  } public void ThreadRun( ) {  for(int looper=1; looper<=quantity; looper++)  cell.WriteToCell(looper); //生產者向操作對象寫入信息 }}public class CellCons{ Cell cell;  int quantity = 1;  public CellCons(Cell box, int request) {  //構造函數  cell = box;   quantity = request;  } public void ThreadRun( ) {  int valReturned;  for(int looper=1; looper<=quantity; looper++)  valReturned=cell.ReadFromCell( );//消費者從操作對象中讀取信息 }}

然后在下面這個類MonitorSample的Main()函數中,我們要做的就是創建兩個線程分別作為生產者和消費者,使用CellProd.ThreadRun()方法和CellCons.ThreadRun()方法對同一個Cell對象進行操作。

public class MonitorSample{ public static void Main(String[] args) {  int result = 0;  //一個標志位,如果是0表示程序沒有出錯,如果是1表明有錯誤發生  Cell cell = new Cell( );   //下面使用cell初始化CellProd和CellCons兩個類,生產和消費次數均為20次  CellProd prod = new CellProd(cell, 20);   CellCons cons = new CellCons(cell, 20);   Thread producer = new Thread(new ThreadStart(prod.ThreadRun));  Thread consumer = new Thread(new ThreadStart(cons.ThreadRun));  //生產者線程和消費者線程都已經被創建,但是沒有開始執行   try  { producer.Start( ); consumer.Start( );  producer.Join( );  consumer.Join( ); Console.ReadLine();  }  catch (ThreadStateException e)  { //當線程因為所處狀態的原因而不能執行被請求的操作 Console.WriteLine(e);  result = 1;   }  catch (ThreadInterruptedException e)  { //當線程在等待狀態的時候中止 Console.WriteLine(e);  result = 1;   }  //盡管Main()函數沒有返回值,但下面這條語句可以向父進程返回執行結果  Environment.ExitCode = result; }}

在上面的例程中,同步是通過等待Monitor.Pulse()來完成的。首先生產者生產了一個值,而 同一時刻消費者處于等待狀態,直到收到生產者的“脈沖(Pulse)”通知它生產已經完成,此后消費者進入消費狀態,而生產者開始等待消費者完成操作后將 調用Monitor.Pulese()發出的“脈沖”。

它的執行結果很簡單:

Produce: 1
Consume: 1
Produce: 2
Consume: 2
Produce: 3
Consume: 3
...
...
Produce: 20
Consume: 20
 
事實上,這個簡單的例子已經幫助我們解決了多線程應用程序中可能出現的大問題,只要領悟了解決線程間沖突的基本方法,很容易把它應用到比較復雜的程序中去。

希望本文所述對大家的C#程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美激情视频三区| 色先锋资源久久综合5566| 国产精品中文字幕在线| 亚洲free性xxxx护士hd| 久久91亚洲人成电影网站| 欧美一级黄色网| 国内精品久久久久久久久| 亚洲美女免费精品视频在线观看| 亚洲国产精彩中文乱码av在线播放| 国产精品69av| 日韩精品中文字幕在线播放| 国产在线精品成人一区二区三区| 国产精品爽爽爽| 欧美多人爱爱视频网站| 亚洲bt欧美bt日本bt| 亚洲成人精品久久久| 91wwwcom在线观看| 欧美日韩国产123| 日韩专区在线播放| 北条麻妃久久精品| 亚洲国产91精品在线观看| 国产成人极品视频| 久久久久久久久久久91| 亚洲天堂成人在线视频| 日韩中文字幕精品视频| 国产欧美一区二区三区久久人妖| 国产精品自产拍在线观| 精品国产网站地址| 久久精品人人做人人爽| 日韩高清电影免费观看完整版| 久久国产精品免费视频| 91免费看片网站| 精品福利一区二区| 国产91精品久久久| 日韩天堂在线视频| 日韩美女av在线| 国产欧美久久久久久| 美女扒开尿口让男人操亚洲视频网站| 欧美成人全部免费| 久久久久久久香蕉网| 亚洲天堂免费视频| 日韩中文在线中文网三级| 亚洲国产精品专区久久| 亚洲第一网中文字幕| 欧洲一区二区视频| www.国产一区| 欧美精品在线观看91| 国产欧美一区二区三区视频| 亚洲精品欧美日韩专区| 5252色成人免费视频| 久久色在线播放| 久久亚洲精品国产亚洲老地址| 精品国产一区二区三区久久久| 色婷婷av一区二区三区久久| 欧洲成人午夜免费大片| 久久久www成人免费精品张筱雨| 欧美亚洲国产日韩2020| 亚洲国产成人精品久久久国产成人一区| 亚洲在线观看视频网站| 91九色蝌蚪国产| 亚洲国产精品大全| 中文字幕综合在线| 欧美日韩人人澡狠狠躁视频| 国产色婷婷国产综合在线理论片a| 久久在线精品视频| 国产视频精品久久久| 国产精品96久久久久久又黄又硬| 97精品国产97久久久久久春色| 欧美高清在线视频观看不卡| 亚洲白虎美女被爆操| 日韩欧美中文字幕在线播放| 日韩欧美亚洲范冰冰与中字| 2019日本中文字幕| 综合国产在线观看| 中文字幕在线日韩| 亚洲欧洲在线播放| 亚洲精品日韩av| 国产在线拍揄自揄视频不卡99| 国产一区二区三区欧美| 欧美一乱一性一交一视频| 九九热99久久久国产盗摄| 久久综合久久美利坚合众国| 91精品视频在线| 91夜夜未满十八勿入爽爽影院| 日韩中文字幕免费| 欧美放荡办公室videos4k| 国产精品夜色7777狼人| 久久好看免费视频| 精品福利免费观看| 最近中文字幕2019免费| 亚洲精品免费一区二区三区| 91精品在线观| 尤物yw午夜国产精品视频明星| 92国产精品视频| 亚洲va欧美va国产综合剧情| 色综合老司机第九色激情| 国产精品午夜一区二区欲梦| 日韩av中文字幕在线免费观看| 午夜免费日韩视频| 91嫩草在线视频| 国产精品免费视频久久久| 欧美精品手机在线| 国产精品一区二区三| 欧美高清视频一区二区| 久久理论片午夜琪琪电影网| 日韩一区二区在线视频| 精品亚洲aⅴ在线观看| 97福利一区二区| 日本三级久久久| 国产丝袜精品第一页| 成人免费高清完整版在线观看| 国产精品爱啪在线线免费观看| 69影院欧美专区视频| 欧美另类交人妖| 91精品国产九九九久久久亚洲| 久久久久久久久久av| 国产98色在线| 久久久久久久国产精品视频| 亚洲精品一区二区网址| 亚洲综合av影视| 欧美精品日韩www.p站| 久久成人在线视频| 国产精品第七影院| 亚洲第一精品夜夜躁人人躁| 国产精品亚洲网站| 亚洲伊人久久大香线蕉av| 性欧美在线看片a免费观看| 国产精品久久久久秋霞鲁丝| 亚洲精品中文字幕有码专区| 欧美成在线观看| 亚洲2020天天堂在线观看| 国产在线久久久| 亚洲欧美日韩视频一区| 国产精品手机播放| 亚洲国产精品99| 亚洲色图第一页| 91精品国产自产在线老师啪| 日韩中文有码在线视频| 亚洲欧美日韩天堂一区二区| 性欧美xxxx视频在线观看| 5566成人精品视频免费| 最近2019年手机中文字幕| 一区二区三区亚洲| 亚洲男人天堂久| 欧美一级视频一区二区| 成人免费淫片aa视频免费| 国产日韩欧美日韩大片| 欧美日韩中文字幕在线| 国产精品久久久久久久久久新婚| 26uuu亚洲伊人春色| 国产精品入口夜色视频大尺度| 国产一区二区三区在线播放免费观看| 国产午夜精品久久久| 91亚洲精品视频| 亚洲人成电影网站| 亚洲精品999| 欧美成人午夜激情在线| 亚洲国产天堂网精品网站| 国产精品日韩av| 欧美激情按摩在线| 国产精品视频专区| 亚洲国产精品久久久| 欧美亚洲激情在线| 久久久久久久久91|