国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > C# > 正文

詳細(xì)解析C#多線程同步事件及等待句柄

2019-10-29 21:19:46
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

最近搗鼓了一下多線程的同步問(wèn)題,發(fā)現(xiàn)其實(shí)C#關(guān)于多線程同步事件處理還是很靈活,這里主要寫(xiě)一下,自己測(cè)試的一些代碼,涉及到了AutoResetEvent 和 ManualResetEvent,當(dāng)然還有也簡(jiǎn)要提了一下System.Threading.WaitHandle.WaitOne 、System.Threading.WaitHandle.WaitAny和System.Threading.WaitHandle.WaitAll ,下面我們一最初學(xué)者的角度來(lái)看,多線程之間的同步。

假設(shè)有這樣的一個(gè)場(chǎng)景,主線程開(kāi)了一個(gè)子線程,讓子線程等著,等主線程完成了某件事情時(shí)再通知子線程去往下執(zhí)行,這里關(guān)鍵就在于這個(gè)怎讓子線程等著,主線程怎通知子線程,一般情況下我們不難想到用一個(gè)公共變量,于是咱們就有了下面的代碼:

using System; using System.Collections.Generic; using System.Text; using System.Threading;  namespace AutoResetEventTest {   class Class1   {     static bool flag = true;      static void DoWork()     {       Console.WriteLine("  worker thread started, now waiting on event...");       while (flag)       {        }       Console.WriteLine("  worker thread reactivated, now exiting...");     }      static void Main()     {       Console.WriteLine("main thread starting worker thread...");       Thread t = new Thread(DoWork);       t.Start();        Console.WriteLine("main thrad sleeping for 1 second...");       Thread.Sleep(1000);        Console.WriteLine("main thread signaling worker thread...");       flag = false;     }   } } 

雖然目的達(dá)到了,但是看著這代碼就糾結(jié),下面該是我們的主角上場(chǎng)了,AutoResetEvent 和 ManualResetEvent,關(guān)于這兩者我們暫且認(rèn)為是差不多了,稍后我會(huì)介紹他們的不同,這里以AutoResetEvent為例,其實(shí)很多官方的說(shuō)法太過(guò)于抽象,這里通俗地講,可以認(rèn)為AutoResetEvent就是一個(gè)公共的變量(盡管它是一個(gè)事件),創(chuàng)建的時(shí)候可以設(shè)置為false,然后在要等待的線程使用它的WaitOne方法,那么線程就一直會(huì)處于等待狀態(tài),只有這個(gè)AutoResetEvent被別的線程使用了Set方法,也就是要發(fā)通知的線程使用了它的Set方法,那么等待的線程就會(huì)往下執(zhí)行了,Set就是發(fā)信號(hào),WaitOne是等待信號(hào),只有發(fā)了信號(hào),等待的才會(huì)執(zhí)行。如果不發(fā)的話,WaitOne后面的程序就永遠(yuǎn)不會(huì)執(zhí)行。好下面看用AutoResetEvent改造上面的程序:

using System; using System.Collections.Generic; using System.Text; using System.Threading;  namespace AutoResetEventTest {   class Class2   {     static AutoResetEvent mEvent=new AutoResetEvent(false);     //static ManualResetEvent mEvent = new ManualResetEvent(false);      static void DoWork()     {       Console.WriteLine("  worker thread started, now waiting on event...");       mEvent.WaitOne();       Console.WriteLine("  worker thread reactivated, now exiting...");     }      static void Main()     {       Console.WriteLine("main thread starting worker thread...");       Thread t = new Thread(DoWork);       t.Start();        Console.WriteLine("main thrad sleeping for 1 second...");       Thread.Sleep(1000);        Console.WriteLine("main thread signaling worker thread...");       mEvent.Set();     }   } } 

這時(shí)代碼是不是清爽多了,這里其實(shí)你還會(huì)看到,把上面的AutoResetEvent換成ManualResetEvent也是沒(méi)有問(wèn)題的,那么它兩之間的區(qū)別是什么呢?個(gè)人認(rèn)為它們最大的區(qū)別在于,無(wú)論何時(shí),只要 AutoResetEvent 激活線程,它的狀態(tài)將自動(dòng)從終止變?yōu)榉墙K止。相反,ManualResetEvent 允許它的終止?fàn)顟B(tài)激活任意多個(gè)線程,只有當(dāng)它的 Reset 方法被調(diào)用時(shí)才還原到非終止?fàn)顟B(tài)。開(kāi)下面的代碼:

using System; using System.Collections.Generic; using System.Text; using System.Threading;  namespace AutoResetEventTest {   class Class3   {     static AutoResetEvent mEvent = new AutoResetEvent(false);     //static ManualResetEvent mEvent = new ManualResetEvent(false);      static void DoWork()     {       Console.WriteLine("  worker thread started, now waiting on event...");       for (int i = 0; i < 3; i++)       {         mEvent.WaitOne();         //mEvent.Reset();         Console.WriteLine("  worker thread reactivated, now exiting...");       }     }      static void Main()     {       Console.WriteLine("main thread starting worker thread...");       Thread t = new Thread(DoWork);       t.Start();        for (int i = 0; i < 3; i++)       {         Thread.Sleep(1000);         Console.WriteLine("main thread signaling worker thread...");         mEvent.Set();       }     }   } } 

如果你想僅僅把AutoResetEvent換成ManualResetEvent的話,你發(fā)現(xiàn)輸出就會(huì)亂套了,為什么呢?

假如有autoevent.WaitOne()和manualevent.WaitOne(),當(dāng)線程得到信號(hào)后都得以繼續(xù)執(zhí)行。差別就在調(diào)用后,autoevent.WaitOne()每次只允許一個(gè)線程進(jìn)入,當(dāng)某個(gè)線程得到信號(hào)(也就是有其他線程調(diào)用了autoevent.Set()方法后)后,autoevent會(huì)自動(dòng)又將信號(hào)置為不發(fā)送狀態(tài),則其他調(diào)用WaitOne的線程只有繼續(xù)等待,也就是說(shuō),autoevent一次只喚醒一個(gè)線程。而manualevent則可以喚醒多個(gè)線程,當(dāng)某個(gè)線程調(diào)用了set方法后,其他調(diào)用waitone的線程獲得信號(hào)得以繼續(xù)執(zhí)行,而manualevent不會(huì)自動(dòng)將信號(hào)置為不發(fā)送,也就是說(shuō),除非手工調(diào)用了manualevent.Reset()方法,否則manualevent將一直保持有信號(hào)狀態(tài),manualevent也就可以同時(shí)喚醒多個(gè)線程繼續(xù)執(zhí)行。

在上面代碼中,如果將AutoResetEvent換成ManualResetEvent的話,只要要在waitone后面做下reset,就會(huì)達(dá)到同樣的效果。

之后咱們?cè)賮?lái)個(gè)簡(jiǎn)單的例子:

using System; using System.Collections.Generic; using System.Text; using System.Threading;  namespace AutoResetEventTest {   class Class4   {     public static AutoResetEvent mEvent = new AutoResetEvent(false);      public static void trmain()     {       Thread tr = Thread.CurrentThread;       Console.WriteLine("thread: waiting for an event");       mEvent.WaitOne();       Console.WriteLine("thread: got an event");       for (int x = 0; x < 10; x++)       {         Thread.Sleep(1000);         Console.WriteLine(tr.Name + ": " + x);       }     }     static void Main(string[] args)     {       Thread thrd1 = new Thread(new ThreadStart(trmain));       thrd1.Name = "thread1";       thrd1.Start();       for (int x = 0; x < 10; x++)       {         Thread.Sleep(900);         Console.WriteLine("Main:" + x);         if (5 == x) mEvent.Set();       }       while (thrd1.IsAlive)       {         Thread.Sleep(1000);         Console.WriteLine("Main: waiting for thread to stop");       }     }   } } 

是不是更有感覺(jué)了?之后咱來(lái)看看另外幾個(gè)東東:

System.Threading.WaitHandle.WaitOne 使線程一直等待,直到單個(gè)事件變?yōu)榻K止?fàn)顟B(tài);

System.Threading.WaitHandle.WaitAny 阻止線程,直到一個(gè)或多個(gè)指示的事件變?yōu)榻K止?fàn)顟B(tài);

System.Threading.WaitHandle.WaitAll 阻止線程,直到所有指示的事件都變?yōu)榻K止?fàn)顟B(tài)。

然后再來(lái)個(gè)例子,以WaitAll使用為例:

using System; using System.Collections.Generic; using System.Text; using System.Threading;  namespace AutoResetEventTest {   class other   {     static void Main(string[] args)     {       Random randomGenerator = new Random();       AutoResetEvent[] resets=new AutoResetEvent[5];        for (int i = 0; i < 5; i++)       {         resets[i] = new AutoResetEvent(false);         int wTime = randomGenerator.Next(10)+1;          worker w = new worker(wTime, resets[i]);          Thread thrd1 = new Thread(new ThreadStart(w.work));         thrd1.Start();        }       WaitHandle.WaitAll(resets);       Console.WriteLine("ALL worker done - main exiting.");     }    }    public class worker   {     public string name;     public int wTime;     public AutoResetEvent mEvent;      public worker(int w, AutoResetEvent m)     {       name = w.ToString();       wTime = w * 1000;       mEvent = m;     }      public void work()     {       Console.WriteLine(name + " worker thread waiting for " + wTime + "....");       Thread.Sleep(wTime);       Console.WriteLine(name + " worker thread back...");       mEvent.Set();     }   } } 

簡(jiǎn)單來(lái)說(shuō)就是,開(kāi)了5個(gè)線程,每個(gè)線程隨機(jī)休眠若干秒,都完成后通知主線程退出,這里就開(kāi)了一個(gè)AutoResetEvent數(shù)組,主線程就WaitHandle.WaitAll(resets) ,子線程休眠完后就Set1個(gè)AutoResetEvent,最后都Set完后,主線程就會(huì)往下執(zhí)行。最后最后再來(lái)個(gè)買(mǎi)書(shū)付款取貨的例子,加深理解:

using System; using System.Collections.Generic; using System.Text; using System.Threading;  namespace AutoResetEventTest {   class Program   {     const int numIterations = 10;     static AutoResetEvent myResetEvent = new AutoResetEvent(false);     static AutoResetEvent ChangeEvent = new AutoResetEvent(false);     //static ManualResetEvent myResetEvent = new ManualResetEvent(false);     //static ManualResetEvent ChangeEvent = new ManualResetEvent(false);     static int number; //這是關(guān)鍵資源      static void Main()     {       Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc));       payMoneyThread.Name = "付錢(qián)線程";       Thread getBookThread = new Thread(new ThreadStart(GetBookProc));       getBookThread.Name = "取書(shū)線程";       payMoneyThread.Start();       getBookThread.Start();        for (int i = 1; i <= numIterations; i++)       {         Console.WriteLine("買(mǎi)書(shū)線程:數(shù)量{0}", i);         number = i;         //Signal that a value has been written.         myResetEvent.Set();         //ChangeEvent.Set();         Thread.Sleep(10);       }       payMoneyThread.Abort();       getBookThread.Abort();     }      static void PayMoneyProc()     {       while (true)       {         myResetEvent.WaitOne();         //myResetEvent.Reset();         Console.WriteLine("{0}:數(shù)量{1}", Thread.CurrentThread.Name, number);         ChangeEvent.Set();       }     }     static void GetBookProc()     {       while (true)       {         ChangeEvent.WaitOne();         //ChangeEvent.Reset();                 Console.WriteLine("{0}:數(shù)量{1}", Thread.CurrentThread.Name, number);         Console.WriteLine("------------------------------------------");         //Thread.Sleep(0);       }     }   } } 

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到c#教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 本溪市| 万盛区| 桦甸市| 舟山市| 宁明县| 垣曲县| 札达县| 大方县| 海宁市| 临泽县| 正蓝旗| 茶陵县| 东光县| 武功县| 胶州市| 油尖旺区| 会昌县| 霍城县| 石渠县| 定南县| 盐亭县| 电白县| 黑龙江省| 东乡族自治县| 德格县| 清水县| 张家港市| 石嘴山市| 土默特右旗| 连江县| 新晃| 明水县| 忻州市| 兰溪市| 平利县| 穆棱市| 七台河市| 彰武县| 桓仁| 论坛| 内江市|