【转】细说.NET 中的多线程 (一 概念)
為什么使用多線程
?
1.使用戶界面能夠及時響應(yīng)用戶的輸入
當(dāng)某個應(yīng)用程序在進(jìn)行大量運(yùn)算時候,為了保證應(yīng)用程序能夠隨時響應(yīng)客戶的輸入,這個時候我們往往需要讓大量運(yùn)算和響應(yīng)用戶輸入這兩個行為在不同的線程中進(jìn)行。
2.效率原因
應(yīng)用程序經(jīng)常需要等待一些資源,如等待網(wǎng)絡(luò)資源,等待io資源,等待用戶輸入等等。這種情況下使用多線程可以避免CPU長時間處于閑置狀態(tài)。
3.多線程的性能損耗
1)用戶態(tài)、內(nèi)核態(tài)切換性能損耗
線程內(nèi)的資源有兩種運(yùn)行態(tài),即用戶態(tài)和內(nèi)核態(tài)。某些運(yùn)算可以在堆棧上進(jìn)行,這種情況線程是在用戶態(tài)運(yùn)行的。如果需要運(yùn)行一些高權(quán)限的指令,或者某些優(yōu)先級很高的指令需要在操作系統(tǒng)內(nèi)核中進(jìn)行,這個時候線程會運(yùn)行在內(nèi)核態(tài)。出于安全原因,用戶態(tài)和內(nèi)核態(tài)的資源是不能夠互相訪問的,因此在用戶態(tài)和內(nèi)核態(tài)的切換過程中,我們需要進(jìn)行相關(guān)上下文以及變量的復(fù)制,這意味的用戶態(tài)和內(nèi)核態(tài)的切換是以一定的時間消耗為代價的。
2)進(jìn)程上下文切換損耗
由于CPU是以時間片為單位進(jìn)行線程切換,并且CPU的運(yùn)算速度遠(yuǎn)大于內(nèi)存的讀寫速度,因此CPU和內(nèi)存之間通常有兩級緩存,不同的線程的上下文訪問的數(shù)據(jù)往往是不同的,這樣線程的切換需要經(jīng)常頻繁的切換CPU緩存的內(nèi)容,也需要更新線程的調(diào)度信息,這些都是需要花費(fèi)一定的時間的,因此合理的使用多線程,來避免CPU不停的進(jìn)行上下文切換。
System.Thread介紹
創(chuàng)建一個線程
創(chuàng)建每一個線程的時候,CLR都需要進(jìn)行一系列的操作,如初始化線程的本地資源,為線程分配用戶模式和內(nèi)核模式下相應(yīng)的堆棧,加載相應(yīng)的托管,非托管資源等。
最簡單常用的創(chuàng)建線程的方式是使用ThreadStart來創(chuàng)建線程,相關(guān)代碼如下:
ThreadStart只需要一個委托即可,如果你善于使用匿名方法,也可以用匿名方法來代替委托,使用匿名方法的另一個好處是可以通過匿名方法的閉包特性來為新的線程傳遞參數(shù)。
雖然使用匿名方法的閉包特性可以很方便的為線程傳遞參數(shù),但是也往往會帶來一些不容易發(fā)現(xiàn)的問題,如下面的程序,由于i變量的共享,在運(yùn)行的時候輸出會有問題:
正確的寫法應(yīng)該是這樣的:
線程異常的捕獲
如果線程中可能需要捕獲異常,那么我們不能這樣做:
而是這樣做:
System.Thread線程的成員
System.Threading.Thread幫助我們實(shí)現(xiàn)了一些線程的基本操作,如:
| 屬性名稱 | 說明 |
| CurrentContext | 獲取線程正在其中執(zhí)行的當(dāng)前上下文。 |
| CurrentThread | 獲取當(dāng)前正在運(yùn)行的線程。 |
| ExecutionContext | 獲取一個?ExecutionContext?對象,該對象包含有關(guān)當(dāng)前線程的各種上下文的信息。 |
| IsAlive | 獲取一個值,該值指示當(dāng)前線程的執(zhí)行狀態(tài)。 |
| IsBackground | 獲取或設(shè)置一個值,該值指示某個線程是否為后臺線程。 |
| IsThreadPoolThread | 獲取一個值,該值指示線程是否屬于托管線程池。 |
| ManagedThreadId | 獲取當(dāng)前托管線程的唯一標(biāo)識符。 |
| Name | 獲取或設(shè)置線程的名稱。 |
| Priority | 獲取或設(shè)置一個值,該值指示線程的調(diào)度優(yōu)先級。 |
| ThreadState | 獲取一個值,該值包含當(dāng)前線程的狀態(tài)。 |
?
?
| 方法名稱 | 說明 |
| Abort() | 終止本線程。 |
| GetDomain() | 返回當(dāng)前線程正在其中運(yùn)行的當(dāng)前域。 |
| GetDomainId() | 返回當(dāng)前線程正在其中運(yùn)行的當(dāng)前域Id。 |
| Interrupt() | 中斷處于?WaitSleepJoin?線程狀態(tài)的線程。 |
| Join() | 已重載。阻塞調(diào)用線程,直到某個線程終止時為止。 |
| Resume() | 繼續(xù)運(yùn)行已掛起的線程。 |
| Start() | 執(zhí)行本線程。 |
| Suspend() | 掛起當(dāng)前線程,如果當(dāng)前線程已屬于掛起狀態(tài)則此不起作用 |
| Sleep() | 把正在運(yùn)行的線程掛起一段時間。 |
?
前臺線程vs后臺線程
這里我們單獨(dú)提一下前臺線程和后臺線程。在CLR中,線程分為前臺線程和后臺線程,當(dāng)所有前臺的線程執(zhí)行完之后,CLR會強(qiáng)制結(jié)束所有正在運(yùn)行的后臺線程,并且不會出現(xiàn)任何異常。
因此你應(yīng)該使用前臺線程來做一些必須完成的任務(wù),比如把流從內(nèi)存中寫到磁盤上。后臺線程可以做一些不那么重要的事情。一旦線程對象的生命周期開始,你就不能修改IsBackground值。
?
由于線程是非常昂貴的資源,我們經(jīng)常需要控制允許多少線程同時運(yùn)行,如何控制線程的生命周期,如何管理線程,這里我們引入了線程池的概念。
?
細(xì)說.NET中的多線程 (二 線程池)
?
作者:獨(dú)上高樓
出處:http://www.cnblogs.com/myprogram/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
總結(jié)
以上是生活随笔為你收集整理的【转】细说.NET 中的多线程 (一 概念)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019年家庭收入标准是多少?分五个等级
- 下一篇: 【转】WPF默认控件模板的获取和资源词典