《C#.net程序設(shè)計(jì)課件》課件-第十章 進(jìn)程與線程_第1頁(yè)
《C#.net程序設(shè)計(jì)課件》課件-第十章 進(jìn)程與線程_第2頁(yè)
《C#.net程序設(shè)計(jì)課件》課件-第十章 進(jìn)程與線程_第3頁(yè)
《C#.net程序設(shè)計(jì)課件》課件-第十章 進(jìn)程與線程_第4頁(yè)
《C#.net程序設(shè)計(jì)課件》課件-第十章 進(jìn)程與線程_第5頁(yè)
已閱讀5頁(yè),還剩38頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第十章

進(jìn)程與線程C#.net程序設(shè)計(jì)1本章主要內(nèi)容進(jìn)程的創(chuàng)建,綁定,啟動(dòng)和停止。創(chuàng)建線程Thread對(duì)象,以及線程睡眠、中斷和銷毀,線程池ThreadPool類,后臺(tái)線程和前臺(tái)線程。使用Interlocked類,lock語(yǔ)句、Monitor類,同步事件(AutoResetEvent和ManualResetEvent)和等待句柄等實(shí)現(xiàn)線程同步。使用BackgroundWorker實(shí)現(xiàn)后臺(tái)操作的Windows應(yīng)用程序。Windows應(yīng)用程序窗體控件線程安全調(diào)用。進(jìn)程

進(jìn)程是程序在計(jì)算機(jī)上的一次執(zhí)行活動(dòng)。程序是指令的有序集合,其本身沒(méi)有任何運(yùn)行的含義,是一個(gè)靜態(tài)的概念。而進(jìn)程是程序在處理機(jī)上的一次執(zhí)行過(guò)程,它是一個(gè)動(dòng)態(tài)的概念。進(jìn)程可以分為系統(tǒng)進(jìn)程和用戶進(jìn)程。凡是用于完成操作系統(tǒng)各種功能的進(jìn)程是系統(tǒng)進(jìn)程,用戶進(jìn)程就是所有由用戶啟動(dòng)的進(jìn)程。在Windows下,進(jìn)程又被細(xì)化為線程,也就是一個(gè)進(jìn)程下有多個(gè)能獨(dú)立運(yùn)行的更小的單位。創(chuàng)建和綁定到進(jìn)程 使用Process組件,可以查看和管理大部分Windows進(jìn)程任務(wù)。創(chuàng)建Process進(jìn)程的實(shí)例有兩種方法:“工具箱”創(chuàng)建Process組件的實(shí)例然后設(shè)置屬性“StartInfo”節(jié)(其中FileName是進(jìn)程的程序名如Notepad)。編程方式ProcessmyProcess=newProcess();

綁定到現(xiàn)有進(jìn)程的方法是調(diào)用GetProcessesByName或GetProcessById方法來(lái)填充進(jìn)程數(shù)組,然后使用索引屬性值來(lái)操作數(shù)組中的單個(gè)進(jìn)程。如:Process[]myProcesses=Process.GetProcessesByName("Notepad");myProcesses[0].CloseMainWindow();進(jìn)程啟動(dòng)進(jìn)程在Windows系統(tǒng)中啟動(dòng)一個(gè)進(jìn)程就是運(yùn)行一個(gè)程序,如運(yùn)行一個(gè)記事本程序等,停止進(jìn)程就是關(guān)閉一個(gè)正在運(yùn)行的程序。啟動(dòng)進(jìn)程有以下兩種方法:設(shè)置由進(jìn)程Process實(shí)例的StartInfo屬性的啟動(dòng)信息,如進(jìn)程執(zhí)行文件,調(diào)用Process實(shí)例的Start方法來(lái)啟動(dòng)進(jìn)程,代碼如下:ProcessmyProcess=newProcess();myProcess.StartInfo.FileName="D:\ProgramFiles\MicrosoftOffice\OFFICE11\WINWORD.EXE"myProcess.StartInfo.WindowStyle= ProcessWindowStyle.MaximizedmyProcess.Start()通過(guò)向Process類Start靜態(tài)方法傳遞FileName參數(shù)來(lái)啟動(dòng)進(jìn)程:ProcessmyProcess=Process.Start("Notepad.exe")進(jìn)程停止進(jìn)程停止進(jìn)程,調(diào)用GetProcessesByName方法將檢索要停止的進(jìn)程。然后調(diào)用下列方法之一:如果進(jìn)程有用戶界面且正在響應(yīng),則調(diào)用CloseMainWindow方法。如果進(jìn)程無(wú)窗口或有用戶界面但無(wú)響應(yīng),則調(diào)用Kill方法。Process[]myProcesses=Process.GetProcessesByName("Notepad.exe");if(myProcesses[0].Responding)myProcesses[0].CloseMainWindow();elsemyProcesses[0].Kill();進(jìn)程停止進(jìn)程

具體使用以上那個(gè)方法停止進(jìn)程要根據(jù)進(jìn)程是否正在響應(yīng),可以使用

Responding屬性確定進(jìn)程的用戶界面是否正在響應(yīng),如果界面沒(méi)有響應(yīng),則返回false屬性值,有響應(yīng),則返回屬性值為true;如果需要強(qiáng)制凍結(jié)應(yīng)用程序關(guān)閉,該屬性很有用。下面的示例顯示如何確定“記事本”是否正在響應(yīng),然后停止該進(jìn)程。查看運(yùn)行的進(jìn)程: 使用GetProcesses方法的返回Process類型的數(shù)組:Process[]myProcesses=Process.GetProcesses();進(jìn)程例:下面演示如何使用TabControl選項(xiàng)卡控件,并在ListBox列表框中顯示W(wǎng)indows的當(dāng)前進(jìn)程列表。privatevoidAddItems(){//添加所有進(jìn)程列表

try{lstProcessesAddItem.Items.Clear();//清空ListBox列表

//列表框顯示Process進(jìn)程對(duì)象的ProcessName進(jìn)程名

lstProcessesAddItem.DisplayMember="ProcessName";foreach(ProcessprcinProcess.GetProcesses())lstProcessesAddItem.Items.Add(prc);//列表框添加所有當(dāng)前進(jìn)程對(duì)象

lstProcessesAddItem.Sorted=true;}catch(Exceptionexp){MessageBox.Show(exp.Message,this.Text);}}//為lstProcessesAddItem列表框添加SelectedIndexChanged事件的處理方法PrivatevoidlstProcessesAddItem_SelectedIndexChanged(objectsender, System.EventArgse) {//將lstProcessesAddItem列表框添所選的進(jìn)程的文件顯示在lblFileName1標(biāo)簽

try{lblFileName1.Text= ((Process)lstProcessesAddItem.SelectedItem).MainModule.FileName;}catch{lblFileName1.Text=string.Empty;}}線程概述操作系統(tǒng)使用進(jìn)程將它們正在執(zhí)行的不同應(yīng)用程序分開,而進(jìn)程中可以有多個(gè)線程同時(shí)執(zhí)行代碼。C#程序具有一個(gè)默認(rèn)線程(或主線程),此線程執(zhí)行程序中以Main方法開始和結(jié)束的代碼。Main直接或間接執(zhí)行的每一個(gè)命令都由主線程執(zhí)行,當(dāng)Main返回時(shí)此線程也將終止。不過(guò),可以創(chuàng)建輔助線程,以便與主線程一起并行執(zhí)行代碼。這些線程通常稱為輔助線程。輔助線程可以用于執(zhí)行耗時(shí)的任務(wù)或時(shí)間要求緊迫的任務(wù),而不必占用主線程。例如,輔助線程通常用在服務(wù)器應(yīng)用程序中,以便不必等待前面的請(qǐng)求完成即可響應(yīng)傳入的請(qǐng)求。輔助線程還可用于在桌面應(yīng)用程序中執(zhí)行“后臺(tái)”任務(wù),以便使主線程(用于驅(qū)動(dòng)用戶界面元素)保持對(duì)用戶操作的響應(yīng)。線程線程概述

多線程處理解決了吞吐量和響應(yīng)性的問(wèn)題,但同時(shí)也帶來(lái)了資源共享問(wèn)題,如死鎖和爭(zhēng)用狀態(tài)。多線程特別適用于需要不同資源(如文件句柄和網(wǎng)絡(luò)連接)的任務(wù)。為單個(gè)資源分配多個(gè)線程可能會(huì)導(dǎo)致同步問(wèn)題,線程會(huì)被頻繁阻止以等待其他線程,從而與使用多線程的初衷背道而馳。System.Threading命名空間提供了用于線程同步的類。這些類包括Mutex、Monitor、Interlocked、AutoResetEvent和ManualResetEvent。線程創(chuàng)建線程 若要在C#進(jìn)行多線程處理,只需創(chuàng)建一個(gè)將在主線程外執(zhí)行的函數(shù),并讓一個(gè)新的Thread對(duì)象指向該函數(shù)即可。創(chuàng)建新的Thread對(duì)象時(shí),將創(chuàng)建新的輔助線程。Thread類具有接受一個(gè)不帶參數(shù)的ThreadStart委托或帶參數(shù)的ParameterizedThreadStart委托的構(gòu)造函數(shù):這些委托包裝新線程調(diào)用的方法,調(diào)用Thread對(duì)象的Start方法啟動(dòng)新線程,Start方法立即返回。下面是創(chuàng)建二個(gè)新線程的JoinThreadCS項(xiàng)目代碼:classApp{staticvoidMyThreadMethod(){ Console.WriteLine("開始第二線程t2運(yùn)行"); }線程staticvoidMyThreadParaMethod(objectpara){ Console.WriteLine("參數(shù)為{0}第三線程t3,運(yùn)行.",para);}staticvoidMain(){Console.WriteLine("主線程運(yùn)行");//MyThreadMethod方法是第二線程t2入口,MyThreadParaMethod//是第三線程t3入口

Threadt2=newThread(newThreadStart(MyThreadMethod));Threadt3=newThread(new ParameterizedThreadStart(MyThreadParaMethod));t2.Start();//開始第二線程t2運(yùn)行MyThreadMethod()方法

t3.Start(“AAA”);//等待第三線程t3運(yùn)行 //MyThreadParaMethod("AAA")方法

t2.Join();//等待第二線程t2的結(jié)束

t3.Join();//等待第三線程t3的結(jié)束

Console.WriteLine("第二線程t2和第三線程t3的結(jié)束");}}線程Sleep、Interrupt和Abort 調(diào)用Thread.Sleep方法會(huì)導(dǎo)致當(dāng)前線程立即阻止,阻止時(shí)間的長(zhǎng)度等于傳遞給Sleep方法的毫秒數(shù),這樣,就會(huì)將其運(yùn)行時(shí)間片中剩余的部分讓與另一個(gè)線程。Timeout.Infinite將使線程休眠,直到被另一個(gè)線程調(diào)用該休眠線程的Thread.Interrupt方法中斷,或被Thread.Abort方法終止。如果調(diào)用Interrupt時(shí)此線程當(dāng)前未于等待、休眠狀態(tài)中,則下次開始阻止時(shí)將被中斷。Abort方法用于永久地停止托管線程。調(diào)用Abort時(shí),在目標(biāo)線程中引發(fā)ThreadAbortException。下面是InterruptThread項(xiàng)目的代碼:線程usingSystem.ThreadingclassApp{staticvoidMyThreadMethod(){try{ Thread.Sleep(Timeout.Infinite);//永久睡眠

}catch(ThreadInterruptedExceptionex){ Console.WriteLine(ex.ToString());}Console.WriteLine("第二線程t2運(yùn)行");}staticvoidMyThreadParaMethod(objectpara){try{ Thread.Sleep(Timeout.Infinite); }catch(ThreadAbortExceptionex){ Console.WriteLine(ex.ToString());Thread.ResetAbort();//清除Abort異常,否則重新拋出異常

}Console.WriteLine(""參數(shù)為{0}第三線程t3,運(yùn)行.",para);}staticvoidMain(){Console.WriteLine("主線程運(yùn)行");//MyThreadMethod方法是第二線程t的入口

Threadt2=newThread(new ThreadStart(MyThreadMethod));Threadt3=newThread(new ParameterizedThreadStart(MyThreadParaMethod));t2.Start();//開始第二線程t2t3.Start("AAA");//開始第三線程t3Thread.Sleep(100);//等待第三線程t3啟動(dòng)

t2.Interrupt();//中斷第二線程睡眠

t3.Abort();//銷毀第三線程t3t2.Join();//等待第二線程t的結(jié)束

t3.Join();//等待第三線程t的結(jié)束

Console.WriteLine("第二線程t2和第三線程t3的結(jié)束");}}使用線程池ThreadPool類線程池是可以用來(lái)在后臺(tái)執(zhí)行多個(gè)任務(wù)的線程集合。線程池通常用于服務(wù)器應(yīng)用程序。每個(gè)傳入請(qǐng)求都將分配給線程池中的一個(gè)線程,因此可以異步處理請(qǐng)求,而不會(huì)占用主線程,也不會(huì)延遲后續(xù)請(qǐng)求的處理。一旦池中的某個(gè)線程完成任務(wù),它將返回到等待線程隊(duì)列中,等待被再次使用。這種重用使應(yīng)用程序可以避免為每個(gè)任務(wù)創(chuàng)建新線程的開銷。線程池通常具有最大線程數(shù)限制。如果所有線程都繁忙,則額外的任務(wù)將放入隊(duì)列中,直到有線程可用時(shí)才能夠得到處理。通過(guò)ThreadPool類可以容易使用線程池。ThreadPool.QueueUserWorkItem(WaitCallback,object)方法是將WaitCallback委托的方法排入隊(duì)列以便執(zhí)行,并指定包含該方法所用的數(shù)據(jù)對(duì)象object參數(shù)。ThreadPool.QueueUserWorkItem(WaitCallback)方法是不帶數(shù)據(jù)參數(shù)的。線程例:是PoolsCS項(xiàng)目的PoolsSample.cs代碼:publicclassExample{publicstaticvoidMain(){ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));Thread.Sleep(1000);//如果主線程提前結(jié)束,線程池作為后臺(tái)線程也終止

Console.WriteLine("Mainthreadexits.");}staticvoidThreadProc(objectstateInfo){//無(wú)數(shù)據(jù)對(duì)象傳入QueueUserWorkItem,所以stateInfo是null.Console.WriteLine("Hellofromthethreadpool.");}}后臺(tái)線程與前臺(tái)線程后臺(tái)線程與前臺(tái)線程的唯一區(qū)別是后臺(tái)線程不會(huì)使托管執(zhí)行環(huán)境處于運(yùn)行狀態(tài),也就是說(shuō)一旦所有前臺(tái)線程在托管進(jìn)程中被停止,系統(tǒng)將停止所有后臺(tái)線程并終止程序運(yùn)行。使用Thread.IsBackground屬性確定線程是后臺(tái)線程還是前臺(tái)線程,或更改其狀態(tài)。通過(guò)將其IsBackground屬性設(shè)置為true,可在任何時(shí)候?qū)⒕€程更改為后臺(tái)線程。通過(guò)創(chuàng)建并啟動(dòng)新的Thread對(duì)象而生成的所有線程都默認(rèn)為前臺(tái)線程。線程池線程是后臺(tái)線程,每個(gè)線程都使用默認(rèn)堆棧大小,以默認(rèn)的優(yōu)先級(jí)運(yùn)行,并處于多線程單元中。每個(gè)進(jìn)程只有一個(gè)線程池對(duì)象。對(duì)于多數(shù)任務(wù),通過(guò)將執(zhí)行請(qǐng)求以線程池線程的方式排隊(duì),可以降低復(fù)雜性。線程線程同步線程的異步特性意味著必須協(xié)調(diào)對(duì)資源的訪問(wèn)。否則,兩個(gè)或更多的線程可能在同一時(shí)間訪問(wèn)相同的資源,結(jié)果將產(chǎn)生不可預(yù)知的數(shù)據(jù)損壞。以下描述多線程應(yīng)用程序中同步資源訪問(wèn)的方法。對(duì)于整數(shù)數(shù)據(jù)類型的簡(jiǎn)單操作,可以用Interlocked類的成員來(lái)實(shí)現(xiàn)線程同步。對(duì)于其他所有數(shù)據(jù)類型和非線程安全的資源,可以分別使用lock語(yǔ)句、Monitor類監(jiān)視器,同步事件(AutoResetEvent和ManualResetEvent)和等待句柄,以及Mutex類執(zhí)行多線程的同步處理。線程同步Interlocked類互鎖操作Interlocked類提供這樣一些方法,即同步對(duì)多個(gè)線程共享的變量的訪問(wèn)的方法。Interlocked類提供了以下操作:Add方法returnValue=Interlocked.Add(reflocation1,value);向變量location1添加一個(gè)整數(shù)值value并返回該變量的新值。Increment和Decrement方法遞增或遞減某個(gè)變量并返回結(jié)果值。returnValue=Interlocked.Increment(reflocation)或Interlocked.Decrement(reflocation)。線程同步Interlocked類互鎖操作Exchange方法returnValue=Interlocked.Exchange(reflocation1,value);執(zhí)行指定變量值的交換,返回該值并將其替換為新值。參數(shù)location1要設(shè)置為新值value,返回值returnValue為location1中的原始值。CompareExchange方法returnValue=Interlocked.CompareExchange(reflocation1,value,comparand);參數(shù)location1其值將與comparand進(jìn)行比較,相等時(shí)value替換location1的值,返回值returnValue為location1中的原始值。Exchange和CompareExchange方法支持引用類型,重載支持Int32、Int64、IntPtr、Single和Double值類型的參數(shù)。線程同步下面時(shí)InterlockedExchange項(xiàng)目提供了Interlocked.Exchange的例子,代碼如下:classMyInterlockedExchangeExampleClassprivatestaticintusingResource=0;//0表示UseResource方法不被//使用,1正在使用。

privateconstintnumThreadIterations=5;//每個(gè)線程將有5次訪問(wèn)//UseResource()privateconstintnumThreads=10;//將有10個(gè)線程同時(shí)訪問(wèn)//MyThreadProc()staticvoidMain(){ThreadmyThread;Randomrnd=newRandom();//Random類表示偽隨機(jī)數(shù)生成器

for(inti=0;i<numThreads;i++){myThread=newThread(newThreadStart(MyThreadProc));myThread.Name=String.Format("Thread{0}",i+1);Thread.Sleep(rnd.Next(0,1000));//睡眠隨機(jī)生成1秒內(nèi)時(shí)間

myThread.Start();/啟動(dòng)線程,即調(diào)用MyThreadProc()}}

privatestaticvoidMyThreadProc(){for(inti=0;i<numThreadIterations;i++){UseResource();Thread.Sleep(1000);//睡眠1秒

}}staticboolUseResource(){//0表示該方法不被使用,1正在使用不能執(zhí)行。

if(0==Interlocked.Exchange(refusingResource,1)){//usingResource=0為真

Console.WriteLine("{0}獲取鎖",Thread.CurrentThread.Name);Thread.Sleep(500);Console.WriteLine("{0}退出鎖",Thread.CurrentThread.Name);Interlocked.Exchange(refusingResource,0);//解鎖singResource:1->0

returntrue;}elseConsole.WriteLine("{0}無(wú)法訪問(wèn),已被鎖", Thread.CurrentThread.Name); returnfalse;}}}InterlockedSample項(xiàng)目提供了Interlocked.Increment和Interlocked.Decrement的例子。classCountClass{privatestaticintunsafeInstanceCount=0;//表示已創(chuàng)建的實(shí)例數(shù)目(不準(zhǔn)確的)privatestaticintsafeInstanceCount=0;//表示已創(chuàng)建的實(shí)例數(shù)目(準(zhǔn)確的)publicCountClass(){//每創(chuàng)建一個(gè)實(shí)例調(diào)用一次

unsafeInstanceCount++;//同時(shí)創(chuàng)建實(shí)例變量操作干擾

Interlocked.Increment(refsafeInstanceCount);//變量操作不被干擾

}~CountClass(){//每銷毀一個(gè)實(shí)例調(diào)用一次

unsafeInstanceCount--;//同時(shí)創(chuàng)建實(shí)例變量操作干擾

Interlocked.Decrement(refsafeInstanceCount); //變量操作不被干擾

}}lock

lock關(guān)鍵字可以用來(lái)確保代碼塊完成運(yùn)行,而不會(huì)被其他線程中斷。這是通過(guò)在代碼塊運(yùn)行期間為給定對(duì)象獲取互斥鎖來(lái)實(shí)現(xiàn)的。lock語(yǔ)句以關(guān)鍵字lock開頭,它有一個(gè)作為參數(shù)的對(duì)象,在該參數(shù)的后面還有一個(gè)一次只能由一個(gè)線程執(zhí)行的代碼塊。例如:objectthisLock=newobject();lock(thisLock){//關(guān)鍵的需要同步代碼}線程同步Monitor類 與lock關(guān)鍵字類似,Monitor類也可以防止多個(gè)線程同時(shí)執(zhí)行代碼塊。Monitor.Enter方法允許一個(gè)且僅一個(gè)線程繼續(xù)執(zhí)行后面的語(yǔ)句;其他所有線程都將被阻止,直到執(zhí)行語(yǔ)句的線程調(diào)用Exit。這與使用lock關(guān)鍵字一樣。事實(shí)上,lock關(guān)鍵字就是用Monitor類來(lái)實(shí)現(xiàn)的。等效于上面lock的Monitor代碼如下:System.Objectobj=(System.Object)thisLock;Monitor.Enter(obj);try{//關(guān)鍵的需要同步代碼}finally{Monitor.Exit(obj);}線程同步MonitorSynchronization項(xiàng)目的statements_lock2.cs代碼演示lock語(yǔ)句。classAccount{privateobjectthisLock=newobject();intbalance;Randomr=newRandom();publicAccount(intinitial){balance=initial;}intWithdraw(intamount){//取錢

if(balance<0)thrownewException("負(fù)的余額");lock(thisLock){if(balance>=amount){ Console.WriteLine("取錢之前的余額:"+balance); Console.WriteLine("取錢數(shù)額:-"+amount);balance=balance-amount; Console.WriteLine("取錢之后的余額:"+balance);returnamount;}else return0;//取消取款

}}

publicvoidDoTransactions(){//取款次,數(shù)額以內(nèi)隨機(jī)數(shù)

for(inti=0;i<100;i++){Withdraw(r.Next(1,100));}}}classTest{staticvoidMain(){Thread[]threads=newThread[10];Accountacc=newAccount(1000);//創(chuàng)建一個(gè)余額的帳戶

for(inti=0;i<10;i++){//使用個(gè)線程

Threadt=newThread(newThreadStart(acc.DoTransactions));threads[i]=t;}for(inti=0;i<10;i++){ threads[i].Start();//啟動(dòng)個(gè)線程調(diào)用 DoTransactions()}}}以上代碼使用lock來(lái)同步一個(gè)帳戶同時(shí)取款的并發(fā)處理??梢允褂门c前面lock等效的Monitor的代碼如下:intWithdraw(intamount){if(balance<0)thrownewException("負(fù)的余額");Monitor.Enter(thisLock);try{if(balance>=amount){ Console.WriteLine("取錢之前的余額:"+balance); Console.WriteLine("取錢數(shù)額:-"+amount);balance=balance-amount; Console.WriteLine("取錢之后的余額:"+balance);returnamount;}elsereturn0;//取消取款

}finally{Monitor.Exit(thisLock);}}同步事件和等待句柄

使用lock鎖或Monitor對(duì)于防止同時(shí)執(zhí)行線程的代碼塊很有用,但是這些構(gòu)造不允許一個(gè)線程向另一個(gè)線程傳達(dá)事件。這需要“同步事件”,它是有兩個(gè)狀態(tài)(終止和非終止)的對(duì)象,可以用來(lái)激活和掛起線程。讓線程等待非終止的同步事件可以將線程掛起,將事件狀態(tài)更改為終止可以將線程激活。如果線程試圖等待已經(jīng)終止的事件,則線程將繼續(xù)執(zhí)行,而不會(huì)延遲。 可以通過(guò)調(diào)用一種等待方法,如WaitOne、WaitAny或WaitAll,讓線程等待事件。WaitHandle.WaitOne使線程一直等待,直到單個(gè)事件變?yōu)榻K止?fàn)顟B(tài);WaitHandle.WaitAny阻止線程,直到一個(gè)或多個(gè)指示的事件變?yōu)榻K止?fàn)顟B(tài);WaitHandle.WaitAll阻止線程,直到所有指示的事件都變?yōu)榻K止?fàn)顟B(tài)。當(dāng)調(diào)用事件的Set方法時(shí),事件將變?yōu)榻K止?fàn)顟B(tài)。線程同步MonitorSynchronization項(xiàng)目的Monitor.cs演示AutoResetEvent、Interlocked和lock代碼如下:classResource{privateobjectthisLock=newobject();publicvoidAccess(Int32threadNum){lock(thisLock){Console.WriteLine("開始獲取資源(Thread={0})",threadNum);Thread.Sleep(500);Console.WriteLine("停止獲取資源(Thread={0})",threadNum);}}}classApp{constInt32numThreadCount=5;//線程數(shù)

staticInt32numAsyncOps=numThreadCount;//異步處理次數(shù)

staticAutoResetEventasyncOpsAreDone=newAutoResetEvent(false);staticResourceres=newResource();publicstaticvoidMain(){for(Int32threadNum=0;threadNum<numThreadCount; threadNum++){//啟動(dòng)線程調(diào)用UpdateResource(threadNum)方法

ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateResource),threadNum);}asyncOpsAreDone.WaitOne();//使本線程一直等待,直到單個(gè)事//件變?yōu)榻K止?fàn)顟B(tài)

Console.WriteLine("所有線程結(jié)束");}staticvoidUpdateResource(Objectstate){//線程池調(diào)用的方法

res.Access((Int32)state);if(Interlocked.Decrement(refnumAsyncOps)==0)//是否完成異//步處理次數(shù)

asyncOpsAreDone.Set();//事件變?yōu)榻K止?fàn)顟B(tài),啟動(dòng)主線程

}}BackgroundWorker組件

BackgroundWorker組件能夠在Windows應(yīng)用程序的用戶界面主線程以外的其他線程上異步(“在后臺(tái)”)執(zhí)行耗時(shí)的操作。例如:圖像下載,文件下載和上載等,類似這樣的操作可能導(dǎo)致用戶界面在操作運(yùn)行時(shí)掛起。若要使用BackgroundWorker,只需要告訴該組件要在后臺(tái)執(zhí)行耗時(shí)的輔助方法,然后調(diào)用RunWorkerAsync方法。在輔助方法以異步方式運(yùn)行的同時(shí),主調(diào)用線程繼續(xù)正常運(yùn)行。該方法運(yùn)行完畢,BackgroundWorker激發(fā)RunWorkerCompleted事件向調(diào)用線程發(fā)出后臺(tái)任務(wù)完成消息。BackgroundWorker的WorkerReportsProgress屬性設(shè)置是否允許發(fā)送后臺(tái)進(jìn)度消息的ProgressChanged事件,而WorkerSupportsCancellation屬性設(shè)置是否允許提供一種允許輔助代碼檢測(cè)到是否調(diào)用中斷后臺(tái)進(jìn)程信號(hào)。本例是異步計(jì)算斐波那契數(shù)列程序,演示如使用BackgroundWorker類在“后臺(tái)”執(zhí)行耗時(shí)的計(jì)算,同時(shí)用戶界面保持響應(yīng)。步驟如下:創(chuàng)建項(xiàng)目并設(shè)置窗體創(chuàng)建一個(gè)名為BackgroundWorkerSample的C#Windows應(yīng)用程序項(xiàng)目。將Form1窗體,重命名為FibonacciCalc,按下圖設(shè)計(jì)程序界面。向FibonacciCalc窗體添加兩個(gè)Label,一個(gè)NumericUpDown,兩個(gè)Button控件,一個(gè)ProgressBar控件和一個(gè)BackgroundWorker組件,并按下表設(shè)置它們的屬性。控件名稱屬性屬性值labellabelName,TextName,Text“l(fā)abelCompute”,“Fibonacci(0)”“l(fā)abelResult”,“計(jì)算結(jié)果”NumericUpDownMinimum,Maximum,name1,100,“numericUpDown1”ButtonName,Text“btnStartAsync”,"開始異步"ButtonName,Text“btnCancelAsync”,“取消異步”BackgroundWorkerWorkerReportsProgressWorkerSupportsCancellationtruetrue添加異步事件處理程序 下面為BackgroundWorker組件的異步事件添加事件處理程序。這些事件處理程序調(diào)用后臺(tái)運(yùn)行的計(jì)算斐波那契數(shù)列的耗時(shí)操作。 在FibonacciCalc窗體中聲明兩個(gè)變量,用來(lái)跟蹤進(jìn)度,然后在窗體中創(chuàng)建一個(gè)稱為ComputeFibonacci的新方法。此方法完成實(shí)際計(jì)算斐波那契數(shù)列的工作,并在后臺(tái)運(yùn)行。這個(gè)演示了斐波那契數(shù)列算法的遞歸實(shí)現(xiàn),代碼如下:privateintnumberToCompute=0;privateinthighestPercentageReached=0;longComputeFibonacci(intn,BackgroundWorkerworker,DoWorkEventArgse){if((n<this.numericUpDown1.Minimum)||(n>this.numericUpDown1.Maximum))thrownewArgumentException(string.Format("valuemustbe>={0}and<= {1}",numericUpDown1.Minimum,numericUpDown1.Maximum),"n"); longresult=0; //判斷是否取消異步即是否執(zhí)行了backgroundWorker1.CancelAsync()方法

if(worker.CancellationPending){e.Cancel=true;}else{if(n<2){result=1;}else{result=ComputeFibonacci(n-1,worker,e)+ComputeFibonacci(n-2,worker,e);}//報(bào)告任務(wù)完成百分比

intpercentComplete=(int)((float)n/(float)numberToCompute*100);if(percentComplete>highestPercentageReached){highestPercentageReached=percentComplete;worker.ReportProgress(percentComplete);//觸發(fā)ProgressChanged事件

}}returnresult;}添加btnStartAsync按鈕增加Click事件,啟動(dòng)BackgroundWorker組件的異步DoWork事件。privatevoidbtnStartAsync_Click(objectsender,EventArgse){this.labelResult.Text=String.Empty;this.numericUpDown1.Enabled=false;this.btnStartAsync.Enabled=false;this.btnCancelAsync.Enabled=true;numberToCompute=(int)numericUpDown1.Value;highestPercentageReached=0; //開始異步操作,觸發(fā)DoWork事件

backgroundWorker1.RunWorkerAsync(numberToCompute);}

在BackgroundWorker的DoWork事件處理程序中,添加對(duì)ComputeFibonacci方法的調(diào)用。將DoWorkEventArgs類型e的Argument屬性作為ComputeFibonacci的第一個(gè)參數(shù)。privatevoidbackgroundWorker1_DoWork(objectsender,DoWorkEventArgse){BackgroundWorkerworker=senderasBackgroundWorker;//將計(jì)算結(jié)果賦于e.Result以傳遞給RunWorkerCompleted事件處理程序

//e.Argument是RunWorkerAsync()的參數(shù)numberToComputee.Result=ComputeFibonacci((int)e.Argument,worker,e);}添加進(jìn)度報(bào)告、取消支持和完成報(bào)告添加進(jìn)度報(bào)告,為BackgroundWorker的ProgressChanged事件添加事件處理程序。在ProgressChanged事件處理程序中,用ProgressChangedEventArgs參數(shù)的ProgressPercentage屬性更新ProgressBar進(jìn)程條進(jìn)度顯示。//ProgressChanged事件處理程序,該事件由ReportProgress()方法啟動(dòng)privatevoidbackgroundWorker1_ProgressChanged(objectsender,ProgressChangedEventArgse){//e.ProgressPercentage是ReportProgress()方法的參數(shù)percentCompletegressBar1.Value=e.ProgressPercentage; //設(shè)置界面進(jìn)程條完成百分比}實(shí)現(xiàn)取消支持,當(dāng)計(jì)算時(shí)間太長(zhǎng)而不想繼續(xù)計(jì)算,按“取消異步”可取消計(jì)算,在btnCancelAsync按鈕控件Click事件處理程序中添加取消異步操作代碼。privatevoidbtnCancelAsync_Click(objectsender,EventArgse){ //取消異步按鈕Click事件

this.backgroundWorker1.CancelAsync(); //取消異步使CancellationPending屬性為truethis.btnCancelAsync.Enabled=false;}在BackgroundWorker的DoWork事件處理程序完成后,將觸發(fā)在BackgroundWorker的RunWorkerCompleted事件處理程序中,添加異步操作完成代碼:privatevoidbackgroundWorker1_RunWorkerCompleted(objectsender,RunWorkerCompletedEventArgse){if(e.Error!=null)//處理異常

MessageBox.Show(e.Error.Message);elseif(e.Cancelled)//判斷是否取消異步

labelResult.Text="取消異步";else{//異步操作成功,將結(jié)果e.Re

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論