多線程技術(shù)課件_第1頁
多線程技術(shù)課件_第2頁
多線程技術(shù)課件_第3頁
多線程技術(shù)課件_第4頁
多線程技術(shù)課件_第5頁
已閱讀5頁,還剩43頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、 第六講 C#多線程技術(shù)主要內(nèi)容 6.1 線程概述6.2 .NET對多線程的支持6.3 一個(gè)多線程程序6.4 線程的優(yōu)先級 6.5 線程的同步 6.6 多線程的自動(dòng)管理 6.7 應(yīng)用實(shí)例 6.1 線程概述進(jìn)程:是應(yīng)用程序的一個(gè)運(yùn)行例程,是應(yīng)用程序的一次動(dòng)態(tài)執(zhí)行過程。線程:是進(jìn)程中的一個(gè)執(zhí)行單元;是操作系統(tǒng)分配CPU時(shí)間的基本單元。Windows是一個(gè)支持多線程的系統(tǒng)。一個(gè)進(jìn)程可以包含若干個(gè)線程。多線程的概念多線程:在同一時(shí)間執(zhí)行多個(gè)任務(wù)的功能,稱為多線程或自由線程。多線程的優(yōu)點(diǎn):可以同時(shí)完成多個(gè)任務(wù);可以使程序的響應(yīng)速度更快;可以讓占用大量處理時(shí)間的任務(wù)或當(dāng)前沒有進(jìn)行處理的任務(wù)定期將處理時(shí)間讓

2、給別的任務(wù);可以隨時(shí)停止任務(wù);可以設(shè)置每個(gè)任務(wù)的優(yōu)先級以優(yōu)化程序性能。主要缺點(diǎn):對資源的共享訪問可能造成沖突(對共享資源的訪問進(jìn)行同步或控制) ;程序的整體運(yùn)行速度減慢等等。6.2 .NET對多線程的支持在.NET程序設(shè)計(jì)中,線程是使用Thread類(或Timer類(線程計(jì)數(shù)器)、ThreadPool類(線程池)來處理的,這些類在System.Threading命名空間中:using System.Threading;Thread類:(實(shí)現(xiàn)線程的主要方法)一個(gè)Thread實(shí)例管理一個(gè)線程,即執(zhí)行序列。通過簡單實(shí)例化一個(gè)Thread對象,就可以創(chuàng)建一個(gè)線程,然后通過Thread對象提供的方法對線

3、程進(jìn)行管理。 Timer類:適用于間隔性的完成任務(wù)。ThreadPool:適用于多個(gè)小的線程。Thread類的主要屬性1、CurrentThread:獲取當(dāng)前正在運(yùn)行的線程。2、Name:獲取或設(shè)置線程的名稱。3、Priority:獲取或設(shè)置線程的優(yōu)先級。4、TreadState:獲取或設(shè)置線程的當(dāng)前狀態(tài)。5、IsBackground:指示線程是否為后臺線程。6、IsAlive:指示當(dāng)前線程的執(zhí)行狀態(tài)。7、CurrentContext:獲取線程其中執(zhí)行的當(dāng)前上下文。Thread類中線程的狀態(tài)由Thread類的TreadState屬性來確定:Abort、AbortRequested、BackGr

4、ound、Running、Stopped、StopRequested、Suspended、SuspendRequsted、Unstarted、WaitSleepJoin線程的建立與啟動(dòng)新建一個(gè)線程的過程:只需將其聲明并為其提供線程起始點(diǎn)處的方法委托,再用Thread.Start()方法啟動(dòng)該線程(1)聲明:Thread a;(2)實(shí)例化a=new Thread(new ThreadStart(b);其中,b為新建過程中執(zhí)行的過程名。(3)調(diào)用Thread.Start()方法啟動(dòng)該線程a.Start();例題1:線程的建立和啟動(dòng)using System;using System.Threadin

5、g;public class Apublic void ff()/線程啟動(dòng)時(shí)調(diào)用此方法Console.WriteLine(A.ff()方法在另一個(gè)線程上運(yùn)行!);Thread.Sleep(3000);/將線程阻塞一定時(shí)間Console.WriteLine(終止工作線程調(diào)用此實(shí)例方法!);public static void gg()Console.WriteLine(A.gg()方法在另一個(gè)線程上運(yùn)行!);Thread.Sleep(5000);/將線程阻塞一定時(shí)間Console.WriteLine(終止工作線程調(diào)用此靜態(tài)方法!);public class Bpublic static void

6、 Main()Console.WriteLine(*線程簡單示例!*);A a=new A();Thread s1=new Thread(new ThreadStart(a.ff);s1.Start();Console.WriteLine(啟動(dòng)新線程ff()方法后,被Main()線程調(diào)用!);Thread s2=new Thread(new ThreadStart(A.gg);s2.Start();Console.WriteLine(啟動(dòng)新線程gg()方法后,被Main()線程調(diào)用!);Console.ReadLine();線程的掛起、恢復(fù)與終止線程的掛起(或暫停)(1)調(diào)用Thread.Sl

7、eep()方法將線程掛起。注:Sleep()方法指定的時(shí)間以毫秒為單位。(2)調(diào)用s1.Suspend() 方法將線程掛起區(qū)別:前者為靜態(tài)方法,并且使線程立即暫停一定時(shí)間;后者為實(shí)例方法,不會(huì)使線程立即停止執(zhí)行,直到線程到達(dá)安全點(diǎn)之后,它才將該線程暫停。線程的恢復(fù)與終止調(diào)用Resume()方法將線程恢復(fù);調(diào)用Abort()方法將線程終止;其他與操作線程相關(guān)的方法Join():使一個(gè)線程等待另一個(gè)線程停止Interrupt():中斷處于JoinWaitSleep線程狀態(tài)的線程。 static void DisplayNumbers() / 獲取當(dāng)前運(yùn)行線程的Thread對象實(shí)例 Thread t

8、hisThread = Thread.CurrentThread; Console.WriteLine(線程: + thisThread.Name + 已開始運(yùn)行.); / 循環(huán)計(jì)數(shù)直到結(jié)束,在指定的間隔輸出當(dāng)前計(jì)數(shù)值 for (int i = 1; i = 8 * interval; i+) if (i % interval = 0) Console.WriteLine(thisThread.Name + : 當(dāng)前計(jì)數(shù)為 + i); Console.WriteLine(線程 + thisThread.Name + 完成.); static void Main(string args) / 獲

9、取用戶輸入的數(shù)字 Console.Write(請輸入一個(gè)數(shù)字:); interval = int.Parse(Console.ReadLine(); / 定義當(dāng)前主線程線程對象的名字 Thread thisThread = Thread.CurrentThread; thisThread.Name = Main Thread; / 建立新線程對象 ThreadStart workerStart = new ThreadStart(DisplayNumbers); Thread workerThread = new Thread(workerStart); workerThread.Name =

10、 Worker Thread; workerThread.IsBackground = true;workerThread.Start(); / 啟動(dòng)新線程DisplayNumbers(); / 主線程同步進(jìn)行計(jì)數(shù) 例題3:修改上述例題,對Main()方法做如下修改,觀察修改線程的優(yōu)先級的效果:ThreadStart workerStart = new ThreadStart(DisplayNumbers);Thread workerThread = new Thread(workerStart);workerThread.Name = Worker Thread;workerThread.P

11、riority=ThreadPriority.AboveNormal;結(jié)果:一旦工作線程被啟動(dòng),主線程不再運(yùn)行,直到工作線程結(jié)束后主線程才重新計(jì)算。6.5 線程的同步使用線程的一個(gè)重要方面是同步訪問多個(gè)線程訪問的任何變量。背景:當(dāng)多個(gè)線程共享數(shù)據(jù),其中一個(gè)或多個(gè)線程要修改數(shù)據(jù)時(shí),有可能引起數(shù)據(jù)不統(tǒng)一等問題。同步:是指在某一時(shí)刻只有一個(gè)線程可以訪問某共享數(shù)據(jù)1、同步的含義同步問題的產(chǎn)生,主要是由于在高級語言的源代碼中,大多數(shù)情況下看起來是一條語句,但在最后編譯好的匯編語言機(jī)器碼中則會(huì)被翻譯為許多條語句,從而在操作系統(tǒng)調(diào)度時(shí)被劃分到不同的時(shí)間片中。例如:message += Hello world

12、!;這條語句在C#語法上是一條語句,但在執(zhí)行代碼時(shí),實(shí)際上它涉及到許多操作。需要重新分配內(nèi)存以存儲(chǔ)更長的新字符串,需要設(shè)置變量message使之指向新的內(nèi)存,需要復(fù)制實(shí)際文本等。2、在C#中處理同步通過對指定對象的加鎖和解鎖可以實(shí)現(xiàn)同步代碼段的訪問。在.NET的System.Threading命名空間中提供了Monitor類來實(shí)現(xiàn)加鎖與解鎖。該類中的方法都是靜態(tài)的。如下表:C#中 lock關(guān)鍵字提供了與Monitoy.Enter和Monitoy.Exit同樣的功能,這種方法用在你的代碼段不能被其他獨(dú)立的線程中斷的情況。通過對Monitor類的簡易封裝,lock為同步訪問變量提供了一個(gè)非常簡單的

13、方式,其用法如下:lock(x)/ 使用x的語句lock語句把變量放在圓括號中,以包裝對象,稱為獨(dú)占鎖或排它鎖。當(dāng)執(zhí)行帶有l(wèi)ock關(guān)鍵字的復(fù)合語句時(shí),獨(dú)占鎖會(huì)保留下來。當(dāng)變量被包裝在獨(dú)占鎖中時(shí),其他線程就不能訪問該變量。如果在上面的代碼中使用獨(dú)占鎖,在執(zhí)行復(fù)合語句時(shí),這個(gè)線程就會(huì)失去其時(shí)間片。如果下一個(gè)獲得時(shí)間片的線程試圖訪問變量,就會(huì)被拒絕。Windows會(huì)讓其他線程處于睡眠狀態(tài),直到解除了獨(dú)占鎖為止。例題4:使用lock同步線程。本示例建立了10個(gè)線程using System;using System.Threading;/銀行帳戶類class Account int balance;/余

14、額 Random r = new Random(); public Account(int initial) balance = initial; / 測試交易 public void DoTransactions() / 支取隨機(jī)的金額100次 for (int i = 0; i 100; i+) Withdraw(r.Next(1, 100); class TestApp public static void Main() /建立10個(gè)線程同時(shí)進(jìn)行交易 Thread threads = new Thread10; Account acc = new Account(1000);for (i

15、nt i = 0; i 10; i+) Thread t = new Thread(new ThreadStart(acc.DoTransactions); threadsi = t; for (int i = 0; i 10; i+) threadsi.Start(); Thread thread2=new Thread(new ThreadStart(obj2.gg);thread2.Name=第一個(gè)間隔100ms循環(huán)打印線程;thread2.Start();/thread2.Join();thread1.Start();Console.ReadLine();private void ff

16、()for(int i=0;i10;i+)Console.WriteLine(Thread.CurrentThread.Name+:Current count is +i);Thread.Sleep(40);class Bpublic void gg()for(int i=0;i5;i+) Console.WriteLine(Thread.CurrentThread.Name+ :add +i); Thread.Sleep(100); lock 與Monitor 區(qū)別lock 鎖定一段代碼,Monitor 鎖定一個(gè)對象。當(dāng)多線程公用一個(gè)對象時(shí),也會(huì)出現(xiàn)和公用代碼類似的問題,這種問題就不應(yīng)該使用

17、lock 關(guān)鍵字了,這里需要用到System.Threading 中的一個(gè)類Monitor,我們可以稱之為監(jiān)視器,Monitor 提供了使線程共享資源的方案。Monitor 類可以鎖定一個(gè)對象,一個(gè)線程只有得到這把鎖才可以對該對象進(jìn)行操作。對象鎖機(jī)制保證了在可能引起混亂的情況下一個(gè)時(shí)刻只有一個(gè)線程可以訪問這個(gè)對象。Monitor 必須和一個(gè)具體的對象相關(guān)聯(lián),但是由于它是一個(gè)靜態(tài)的類,所以不能使用它來定義對象,而且它的所有方法都是靜態(tài)的,不能使用對象來引用。下面代碼說明了使用Monitor 鎖定一個(gè)對象的情形:.Queue oQueue=new Queue();.Monitor.Enter(oQ

18、ueue);./現(xiàn)在oQueue 對象只能被當(dāng)前線程操縱了Monitor.Exit(oQueue);/釋放鎖如上所示,當(dāng)一個(gè)線程調(diào)用 Monitor.Enter()方法鎖定一個(gè)對象時(shí),這個(gè)對象就歸它所有了,其它線程想要訪問這個(gè)對象,只有等待它使用Monitor.Exit()方法釋放鎖。(在一個(gè)線程運(yùn)行的代碼里面調(diào)用Monitor.Enter(對象),那么其它線程就不能使用該對象了)為了保證線程最終都能釋放鎖,你可以Monitor.Exit()方法寫在try-catch-finally 結(jié)構(gòu)中的finally代碼塊里。對于任何一個(gè)被 Monitor 鎖定的對象,內(nèi)存中都保存著與它相關(guān)的一些信息:

19、其一是現(xiàn)在持有鎖的線程的引用;其二是一個(gè)預(yù)備隊(duì)列,隊(duì)列中保存了已經(jīng)準(zhǔn)備好獲取鎖的線程;其三是一個(gè)等待隊(duì)列,隊(duì)列中保存著當(dāng)前正在等待這個(gè)對象狀態(tài)改變的隊(duì)列的引用。獲取的過程:當(dāng)擁有對象鎖的線程準(zhǔn)備釋放鎖時(shí),它使用 Monitor.Pulse()方法通知等待隊(duì)列中的第一個(gè)線程,于是該線程被轉(zhuǎn)移到預(yù)備隊(duì)列中,當(dāng)對象鎖被釋放時(shí),在預(yù)備隊(duì)列中的線程可以立即獲得對象鎖。3、同步時(shí)要注意的問題線程同步非常重要,但只在需要時(shí)使用也是非常重要的。因?yàn)檫@會(huì)降低性能。原因有兩個(gè):首先,在對象上放置和解開鎖會(huì)帶來某些系統(tǒng)開銷,但這些系統(tǒng)開銷都非常小。第二個(gè)原因更為重要,線程同步使用得越多,等待釋放對象的線程就越多。如

20、果一個(gè)線程在對象上放置了一個(gè)鎖,需要訪問該對象的其他線程就只能暫停執(zhí)行,直到該鎖被解開,才能繼續(xù)執(zhí)行。因此,在lock塊內(nèi)部編寫的代碼越少越好,以免出現(xiàn)線程同步錯(cuò)誤。lock語句在某種意義上就是臨時(shí)禁用應(yīng)用程序的多線程功能,也就臨時(shí)刪除了多線程的各種優(yōu)勢。6.6多線程的自動(dòng)管理在多線程的程序中,經(jīng)常會(huì)出現(xiàn)兩種情況:一種情況: 應(yīng)用程序中,線程把大部分的時(shí)間花費(fèi)在等待狀態(tài),等待某個(gè)事件發(fā)生,然后才能給予響應(yīng)這一般使用 ThreadPool(線程池)來解決;另一種情況:線程平時(shí)都處于休眠狀態(tài),只是周期性地被喚醒這一般使用 Timer(定時(shí)器)來解決;1、多線程的自動(dòng)管理(定時(shí)器Timer)Time

21、r 類:設(shè)置一個(gè)定時(shí)器,定時(shí)執(zhí)行用戶指定的函數(shù)。定時(shí)器啟動(dòng)后,系統(tǒng)將自動(dòng)建立一個(gè)新的線程,執(zhí)行用戶指定的函數(shù)。初始化一個(gè) Timer 對象:Timer timer = new Timer(timerDelegate, s,1000, 1000);/ 第一個(gè)參數(shù):指定了TimerCallback 委托,表示要執(zhí)行的方法;/ 第二個(gè)參數(shù):一個(gè)包含回調(diào)方法要使用的信息的對象,或者為空引用;/ 第三個(gè)參數(shù):延遲時(shí)間計(jì)時(shí)開始的時(shí)刻距現(xiàn)在的時(shí)間,單位是毫秒,指定為“0”表示立即啟動(dòng)計(jì)時(shí)器;/ 第四個(gè)參數(shù):定時(shí)器的時(shí)間間隔計(jì)時(shí)開始以后,每隔這么長的一段時(shí)間,TimerCallback 所代表的方法將被調(diào)用一

22、次,單位也是毫秒。指定 Timeout.Infinite 可以禁用定期終止。Timer.Change()方法:修改定時(shí)器的設(shè)置。(這是一個(gè)參數(shù)類型重載的方法). timer.Change(1000,2000);2、多線程的自動(dòng)管理(線程池)ThreadPool類提供一個(gè)由系統(tǒng)維護(hù)的線程池(可以看作一個(gè)線程的容器),該容器需要 Windows 2000以上系統(tǒng)支持,因?yàn)槠渲心承┓椒ㄕ{(diào)用了只有高版本的Windows 才有的API 函數(shù)。將線程安放在線程池里,需使用 ThreadPool.QueueUserWorkItem()方法,該方法的原型如下:/將一個(gè)線程放進(jìn)線程池,該線程的Start()方法

23、將調(diào)用WaitCallback 代理對象代表的函數(shù)public static bool QueueUserWorkItem(WaitCallback);/重載的方法如下,參數(shù)object 將傳遞給WaitCallback 所代表的方法public static bool QueueUserWorkItem(WaitCallback, object);ThreadPool 類是一個(gè)靜態(tài)類,你不能也不必要生成它的對象。而且一旦使用該方法在線程池中添加了一個(gè)項(xiàng)目,那么該項(xiàng)目將是無法取消的。在這里你無需自己建立線程,只需把你要做的工作寫成函數(shù),然后作為參數(shù)傳遞給ThreadPool.QueueUser

24、WorkItem()方法就行了,傳遞的方法就是依靠WaitCallback 代理對象,而線程的建立、管理、運(yùn)行等工作都是由系統(tǒng)自動(dòng)完成的.ManualResetEvent 對象ManualResetEvent 對象,該對象就像一個(gè)信號燈,可以利用它的信號來通知其它線程。初始化該對象時(shí),用戶可以指定其默認(rèn)的狀態(tài)(有信號/無信號);在初始化以后,該對象將保持原來的狀態(tài)不變,直到它的 Reset()或者Set()方法被調(diào)用:Reset()方法:將其設(shè)置為無信號狀態(tài);Set()方法:將其設(shè)置為有信號狀態(tài)。WaitOne()方法:使當(dāng)前線程掛起,直到ManualResetEvent 對象處于有信號狀態(tài),

25、此時(shí)該線程將被激活。然后,程序?qū)⑾蚓€程池中添加工作項(xiàng),這些以函數(shù)形式提供的工作項(xiàng)被系統(tǒng)用來初始化自動(dòng)建立的線程。當(dāng)所有的線程都運(yùn)行完了以后,ManualResetEvent.Set()方法被調(diào)用,因?yàn)檎{(diào)用了ManualResetEvent.WaitOne()方法而處在等待狀態(tài)的主線程將接收到這個(gè)信號,于是它接著往下執(zhí)行,完成后邊的工作。6.7 應(yīng)用實(shí)例(兩個(gè)關(guān)于線程或進(jìn)程的例子)綜合例題1:通過Process類獲取系統(tǒng)進(jìn)程列表。運(yùn)行界面如下圖所示:using System.Diagnostics;private void button1_Click(object sender, System.EventArgs e)listBox1.Items.Clear(); listBox1.Items

溫馨提示

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

評論

0/150

提交評論