http://www.cnblogs.com/lmule/archive/2010/08/18/1802774.html
簡(jiǎn)而言之,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.
線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。
另外,進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率。
線程在執(zhí)行過(guò)程中與進(jìn)程還是有區(qū)別的。每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。
從邏輯角度來(lái)看,多線程的意義在于一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒(méi)有將多個(gè)線程看做多個(gè)獨(dú)立的應(yīng)用,來(lái)實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配。這就是進(jìn)程和線程的重要區(qū)別。
進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.
線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.
一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程;同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行.
進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其它進(jìn)程產(chǎn)生影響,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時(shí),耗費(fèi)資源較大,效率要差一些。但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。如果有興趣深入的話,我建議你們看看《現(xiàn)代操作系統(tǒng)》或者《操作系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)》。對(duì)就個(gè)問(wèn)題說(shuō)得比較清楚。
5.1 簡(jiǎn)介
進(jìn)程(process)是一塊包含了某些資源的內(nèi)存區(qū)域。操作系統(tǒng)利用進(jìn)程把它的工作劃分為一些功能單元。
進(jìn)程中所包含的一個(gè)或多個(gè)執(zhí)行單元稱為線程(thread)。進(jìn)程還擁有一個(gè)私有的虛擬地址空間,該空間僅能被它所包含的線程訪問(wèn)。
當(dāng)運(yùn)行.NET程序時(shí),進(jìn)程還會(huì)把被稱為CLR的軟件層包含到它的內(nèi)存空間中。上一章曾經(jīng)對(duì)CLR做了詳細(xì)描述。該軟件層是在進(jìn)程創(chuàng)建期間由運(yùn)行時(shí)宿主載入的(參見(jiàn)4.2.3節(jié))。
線程只能歸屬于一個(gè)進(jìn)程并且它只能訪問(wèn)該進(jìn)程所擁有的資源。當(dāng)操作系統(tǒng)創(chuàng)建一個(gè)進(jìn)程后,該進(jìn)程會(huì)自動(dòng)申請(qǐng)一個(gè)名為主線程或首要線程的線程。主線程將執(zhí)行運(yùn)行時(shí)宿主, 而運(yùn)行時(shí)宿主會(huì)負(fù)責(zé)載入CLR。
應(yīng)用程序(application)是由一個(gè)或多個(gè)相互協(xié)作的進(jìn)程組成的。例如,Visual Studio開(kāi)發(fā)環(huán)境就是利用一個(gè)進(jìn)程編輯源文件,并利用另一個(gè)進(jìn)程完成編譯工作的應(yīng)用程序。
在Windows NT/2000/XP操作系統(tǒng)下,我們可以通過(guò)任務(wù)管理器在任意時(shí)間查看所有的應(yīng)用程序和進(jìn)程。盡管只打開(kāi)了幾個(gè)應(yīng)用程序,但是通常情況下將有大約30個(gè)進(jìn)程同時(shí)運(yùn)行。 事實(shí)上,為了管理當(dāng)前的會(huì)話和任務(wù)欄以及其他一些任務(wù),系統(tǒng)執(zhí)行了大量的進(jìn)程。
5.2 進(jìn)程
5.2.1 簡(jiǎn)介
在運(yùn)行于32位處理器上的32位Windows操作系統(tǒng)中,可將一個(gè)進(jìn)程視為一段大小為4GB(232字節(jié))的線性內(nèi)存空間,它起始于0x00000000結(jié)束于0xFFFFFFFF。這段內(nèi)存空間不能被其他進(jìn)程所訪問(wèn),所以稱為該進(jìn)程的私有空間。這段空間被平分為兩塊,2GB被系統(tǒng)所有,剩下2GB被用戶所有。
如果有N個(gè)進(jìn)程運(yùn)行在同一臺(tái)機(jī)器上,那么將需要N×4GB的海量RAM,還好事實(shí)并非如此。
Windows是按需為每個(gè)進(jìn)程分配內(nèi)存的,4GB是32位系統(tǒng)中一個(gè)進(jìn)程所占空間的上限。
將進(jìn)程所需的內(nèi)存劃分為4KB大小的內(nèi)存頁(yè),并根據(jù)使用情況將這些內(nèi)存頁(yè)存儲(chǔ)在硬盤(pán)上或加載到RAM中,通過(guò)系統(tǒng)的這種虛擬內(nèi)存機(jī)制,我們可以有效地減少對(duì)實(shí)際內(nèi)存的需求量。當(dāng)然這些對(duì)用戶和開(kāi)發(fā)者來(lái)說(shuō)都是透明的。
5.2.2 System.Diagnostics.Process類
System.Diagnostics.Process類的實(shí)例可以引用一個(gè)進(jìn)程,被引用的進(jìn)程包含以下幾種。
該實(shí)例的當(dāng)前進(jìn)程。
本機(jī)上除了當(dāng)前進(jìn)程的其他進(jìn)程。
遠(yuǎn)程機(jī)器上的某個(gè)進(jìn)程。
通過(guò)該類所包含的方法和字段,可以創(chuàng)建或銷毀一個(gè)進(jìn)程,并且可以獲得一個(gè)進(jìn)程的相關(guān)信息。下面將討論一些使用該類實(shí)現(xiàn)的常見(jiàn)任務(wù)。
5.2.3 創(chuàng)建和銷毀子進(jìn)程

下面的程序創(chuàng)建了一個(gè)稱為子進(jìn)程的新進(jìn)程。在這種情況下,初始的進(jìn)程稱為父進(jìn)程。子進(jìn)程啟動(dòng)了一個(gè)記事本應(yīng)用程序。父進(jìn)程的線程在等待1秒后銷毀該子進(jìn)程。該程序的執(zhí)行效果就是打開(kāi)并關(guān)閉記事本。
例5-1

靜態(tài)方法Start()可以使用已存在的Windows文件擴(kuò)展名關(guān)聯(lián)機(jī)制。例如,我們可以利用下面的代碼執(zhí)行同樣的操作。
默認(rèn)情況下,子進(jìn)程將繼承其父進(jìn)程的安全上下文。但還可以使用Process.Start()方法的一個(gè)重載版本在任意用戶的安全上下文中啟動(dòng)該子進(jìn)程,當(dāng)然需要通過(guò)一個(gè)System.Diagnostics. ProcessStartInfo類的實(shí)例來(lái)提供該用戶的用戶名和密碼。
5.2.4 避免在一臺(tái)機(jī)器上同時(shí)運(yùn)行同一應(yīng)用程序的多個(gè)實(shí)例

有些應(yīng)用程序需要這種功能。實(shí)際上,通常來(lái)說(shuō)在同一臺(tái)機(jī)器上同時(shí)運(yùn)行一個(gè)應(yīng)用程序的多個(gè)實(shí)例并沒(méi)有意義。
直到現(xiàn)在,為了在Windows下滿足上述約束,開(kāi)發(fā)者最常用的方法仍然是使用有名互斥體(named mutex)技術(shù)(參見(jiàn)5.7.2節(jié))。然而采用這種技術(shù)來(lái)滿足上述約束存在以下缺點(diǎn):
該技術(shù)具有使互斥體的名字被其他應(yīng)用程序所使用的較小的、潛在的風(fēng)險(xiǎn)。在這種情況下該技術(shù)將不再有效并且會(huì)造成很難檢測(cè)到的bug。
該技術(shù)不能解決我們僅允許一個(gè)應(yīng)用程序產(chǎn)生N個(gè)實(shí)例這種一般的問(wèn)題。
幸而在System.Diagnostics.Process類中擁有GetCurrentProcess()(返回當(dāng)前進(jìn)程)和GetPro- cesses()(返回機(jī)器上所有的進(jìn)程)這樣的靜態(tài)方法。在下面的程序中我們?yōu)樯鲜鰡?wèn)題找到了一個(gè)優(yōu)雅且簡(jiǎn)單的解決方案。
例5-2
通過(guò)方法參數(shù)指定了遠(yuǎn)程機(jī)器的名字后,GetProcesses()方法也可以返回遠(yuǎn)程機(jī)器上所有的進(jìn)程。
5.2.5 終止當(dāng)前進(jìn)程
可以調(diào)用System.Environment類中的靜態(tài)方法Exit(int exitCode)或FailFast(stringmessage)終止當(dāng)前進(jìn)程。Exit()方法是最好的選擇,它將徹底終止進(jìn)程并向操作系統(tǒng)返回指定的退出代碼值。之所以稱為徹底終止是因?yàn)楫?dāng)前對(duì)象的所有清理工作以及finally塊的執(zhí)行都將由不同的線程完成。當(dāng)然,終止進(jìn)程將花費(fèi)一定的時(shí)間。
顧名思義,F(xiàn)ailFast()方法可以迅速終止進(jìn)程。Exit()方法所做的預(yù)防措施將被它忽略。只有一個(gè)包含了指定信息的嚴(yán)重錯(cuò)誤會(huì)被操作系統(tǒng)記錄到日志中。你可能想要在探查問(wèn)題的時(shí)候使用該方法,因?yàn)榭梢詫⒃摮绦虻膹氐捉K止視為數(shù)據(jù)惡化的起因。
5.3 線程
5.3.1 簡(jiǎn)介
一個(gè)線程包含以下內(nèi)容。
一個(gè)指向當(dāng)前被執(zhí)行指令的指令指針;
一個(gè)棧;
一個(gè)寄存器值的集合,定義了一部分描述正在執(zhí)行線程的處理器狀態(tài)的值;
一個(gè)私有的數(shù)據(jù)區(qū)。
所有這些元素都?xì)w于線程執(zhí)行上下文的名下。處在同一個(gè)進(jìn)程中的所有線程都可以訪問(wèn)該進(jìn)程所包含的地址空間,當(dāng)然也包含存儲(chǔ)在該空間中的所有資源。
我們不準(zhǔn)備討論線程在內(nèi)核模式或者用戶模式執(zhí)行的問(wèn)題。盡管.NET以前的Windows一直使用這兩種模式,并且依然存在,但是對(duì).NET Framework來(lái)說(shuō)它們是不可見(jiàn)的。
并行使用一些線程通常是我們?cè)趯?shí)現(xiàn)算法時(shí)的自然反應(yīng)。實(shí)際上,一個(gè)算法往往由一系列可以并發(fā)執(zhí)行的任務(wù)組成。但是需要引起注意的是,使用大量的線程將引起過(guò)多的上下文切換,最終反而影響了性能。
同樣,幾年前我們就注意到,預(yù)測(cè)每18個(gè)月處理器運(yùn)算速度增加一倍的摩爾定律已不再成立。處理器的頻率停滯在3GHz~4GHz上下。這是由于物理上的限制,需要一段時(shí)間才能取得突破。同時(shí),為了在性能競(jìng)爭(zhēng)中不會(huì)落敗,較大的處理器制造商如AMD和Intel目前都將目標(biāo)轉(zhuǎn)向多核芯片。因此我們可以預(yù)計(jì)在接下去的幾年中這種類型的架構(gòu)將廣泛被采用。在這種情況下,改進(jìn)應(yīng)用性能的唯一方案就是合理地利用多線程技術(shù)。
5.3.2 受托管的線程與 Windows線程
必須要了解,執(zhí)行.NET應(yīng)用的線程實(shí)際上仍然是Windows線程。但是,當(dāng)某個(gè)線程被CLR所知時(shí),我們將它稱為受托管的線程。具體來(lái)說(shuō),由受托管的代碼創(chuàng)建出來(lái)的線程就是受托管的線程。如果一個(gè)線程由非托管的代碼所創(chuàng)建,那么它就是非托管的線程。不過(guò),一旦該線程執(zhí)行了受托管的代碼它就變成了受托管的線程。
一個(gè)受托管的線程和非托管的線程的區(qū)別在于,CLR將創(chuàng)建一個(gè)System.Threading.Thread類的實(shí)例來(lái)代表并操作前者。在內(nèi)部實(shí)現(xiàn)中,CLR將一個(gè)包含了所有受托管線程的列表保存在一個(gè)叫做ThreadStore地方。
CLR確保每一個(gè)受托管的線程在任意時(shí)刻都在一個(gè)AppDomain中執(zhí)行,但是這并不代表一個(gè)線程將永遠(yuǎn)處在一個(gè)AppDomain中,它可以隨著時(shí)間的推移轉(zhuǎn)到其他的AppDomain中。關(guān)于AppDomain的概念參見(jiàn)4.1。
從安全的角度來(lái)看,一個(gè)受托管的線程的主用戶與底層的非托管線程中的Windows主用戶是無(wú)關(guān)的。
5.3.3 搶占式多任務(wù)處理
我們可以問(wèn)自己下面這個(gè)問(wèn)題: 我的計(jì)算機(jī)只有一個(gè)處理器,然而在任務(wù)管理器中我們卻可以看到數(shù)以百計(jì)的線程正同時(shí)運(yùn)行在機(jī)器上!這怎么可能呢?
多虧了搶占式多任務(wù)處理,通過(guò)它對(duì)線程的調(diào)度,使得上述問(wèn)題成為可能。調(diào)度器作為Windows內(nèi)核的一部分,將時(shí)間切片,分成一段段的時(shí)間片。這些時(shí)間間隔以毫秒為精度且長(zhǎng)度并不固定。針對(duì)每個(gè)處理器,每個(gè)時(shí)間片僅服務(wù)于單獨(dú)一個(gè)線程。線程的迅速執(zhí)行給我們?cè)斐闪怂鼈冊(cè)谕瑫r(shí)運(yùn)行的假象。我們?cè)趦蓚€(gè)時(shí)間片的間隔中進(jìn)行上下文切換。該方法的優(yōu)點(diǎn)在于,那些正在等待某些Windows資源的線程將不會(huì)浪費(fèi)時(shí)間片,直到資源有效為止。
之所以用搶占式這個(gè)形容詞來(lái)修飾這種多任務(wù)管理方式,是因?yàn)樵诖朔N方式下線程將被系統(tǒng)強(qiáng)制性中斷。那些對(duì)此比較好奇的人應(yīng)該了解到,在上下文切換的過(guò)程中,操作系統(tǒng)會(huì)在下一個(gè)線程將要執(zhí)行的代碼中插入一條跳轉(zhuǎn)到下一個(gè)上下文切換的指令。該指令是一個(gè)軟中斷,如果線程在遇到這條指令前就終止了(例如,它正在等待某個(gè)資源),那么該指定將被刪除而上下文切換也將提前發(fā)生。
搶占式多任務(wù)處理的主要缺點(diǎn)在于,必須使用一種同步機(jī)制來(lái)保護(hù)資源以避免它們被無(wú)序訪問(wèn)。除此之外,還有另一種多任務(wù)管理模型,被稱為協(xié)調(diào)式多任務(wù)管理,其中線程間的切換將由線程自己負(fù)責(zé)完成。該模型普遍認(rèn)為太過(guò)危險(xiǎn),原因在于線程間的切換不發(fā)生的風(fēng)險(xiǎn)太大。如我們?cè)?.2.8節(jié)中所解釋的那樣,該機(jī)制會(huì)在內(nèi)部使用以提升某些服務(wù)器的性能,例如SQL Server2005。但Windows操作系統(tǒng)僅僅實(shí)現(xiàn)了搶占式多任務(wù)處理。
?