(1)線程,有時被稱為輕量級進程塌计,是程序執(zhí)行流的最小單元挺身。一個標準的線程由線程ID,當前指令指針锌仅,寄存器集合和堆棧組成章钾。另外,線程是進程中的一個實體热芹,是被系統(tǒng)獨立調度和分派的基本單位贱傀,線程自己不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源伊脓,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源府寒。
(2)進程(Process)定義了一個執(zhí)行環(huán)境,包括它自己私有的地址空間、一個句柄表椰棘,以及一個安全環(huán)境纺棺;線程(thread)則是一個控制流,有自己的調用棧(call stack)邪狞,記錄了執(zhí)行的歷史祷蝌。每個進程都包含一個或多個線程,當進程被初始化創(chuàng)建時系統(tǒng)為該進程創(chuàng)建第一個線程帆卓;當最后一個線程結束時巨朦,進程也隨之結束。
說道這里就需要說到線程的工作模式:
進程中的線程既可以在用戶模式下運行剑令,也可以在內核模式下運行糊啡。如果一個進程運行在用戶模式下,那么它就只能訪問進程地址空間吁津;如果運行在內核模式下棚蓄,那么它將可以訪問這個地址空間。
用戶級線程
應用程序在操作系統(tǒng)提供的單個控制流的基礎上碍脏,通過在有些控制點(比如系統(tǒng)調用)上分離出一些虛擬的控制流梭依,從而模擬多個控制流的行為。由于應用程序對指令流的控制能力相對較弱典尾,所以役拴,用戶級線程之間的切換往往受線程本身行為以及線程控制點選擇的影響,線程是否能夠公平地獲得處理器時間取決于這些線程的代碼特征钾埂。而且河闰,支持用戶級線程的應用程序代碼很難做到跨平臺移植,以及對于多線程模型的透明褥紫。用戶級線程模型的優(yōu)勢:
(1)線程切換效率高姜性,因為它不涉及系統(tǒng)內核模式和用戶模式之間的切換;
(2)另外一個好處是應用程序可以采用適合自己特點的線程選擇算法髓考,可以根據應用程序的邏輯來定義線程的優(yōu)先級污抬,當線程數量很大時。但是绳军,相對的會增加應用程序代碼的復雜度印机。
內核級線程
指操作系統(tǒng)提供的線程語義,由于操作系統(tǒng)對指令流有完全的控制能力门驾,甚至可以通過硬件終端來強迫一個進程或是線程暫停執(zhí)行射赛,以便把處理器時間移交給其他的進程或是線程,所以奶是,內核級線程有可能應用各種算法來分配處理器時間楣责。線程可以有優(yōu)先級竣灌,高優(yōu)先級的線程被優(yōu)化執(zhí)行,他們可以搶占正在執(zhí)行的低優(yōu)先級線程秆麸。在支持線程語義的操作系統(tǒng)中初嘹,處理器的時間通常是按照線程而非進城來分配的,因此沮趣,系統(tǒng)有必要維護一個全局的線程表屯烦,在線程表中記錄每個線程的寄存器、狀態(tài)以及其他的一些信息房铭。然后驻龟,系統(tǒng)在適當的時候掛起一個正在執(zhí)行的線程,選擇一個新的線程在當前處理器上繼續(xù)執(zhí)行缸匪。
內核級線程的好處:
應用程序無需考慮是夠要在適當的時候把控制權交給其他的線程翁狐,不比擔心自己霸占處理器而導致其他線程得不到處理器時間。因而應用程序只要按照正常的指令來實現自己的邏輯就可以了凌蔬,內核會妥善處理好線程之間的共享處理器的資源分配問題露懒。但是這樣帶來的代價便是需要在用戶模式和內核模式下進行切換:從用戶模式切換到內核模式,再從內核模式切換到用戶模式砂心。在Intel的處理器上可能需要幾百上千和處理器指令周期懈词。
對于線程管理和調度,從籠統(tǒng)來說是這樣的:在Windows的內核結構中计贰,進程和線程的核心機制是在微內核中實現的钦睡,而管理機制是在執(zhí)行體中實現的蒂窒。這是基于機制與策略分工的原則躁倒。例如,線程調度是由微內核來完成洒琢,而線程和進程的創(chuàng)建秧秉、各種管理屬性的設置則是由執(zhí)行體來完成的。
既然線程作為程序執(zhí)行流的最小單元衰抑,那么在Windows中象迎,對于線程的管理和調度線程是這樣的:在Windows NT以后,Windows實現了一個基于優(yōu)先級的搶先式多處理器調度系統(tǒng)呛踊。調度系統(tǒng)總是運行優(yōu)先級最高的就緒線程砾淌。通常線程可在任何可用處理器上運行,但也可限制某線程只能在某處理器上運行谭网。
Windows實現了基于優(yōu)先級的搶占式(Preemptive)線程調度算法汪厨,每個線程都有一個基本優(yōu)先級(base priority)和一個動態(tài)優(yōu)先級(priority)。優(yōu)先級的值處于0~31之間愉择,共分為三個類別:
(1)0級表示系統(tǒng)優(yōu)先級劫乱,為最低優(yōu)先級织中,僅用于零頁面線程
(2)1~15為動態(tài)優(yōu)先級,在某些情況下線程的動態(tài)優(yōu)先級可以在此范圍內進行微調衷戈,例如當一個前臺線程從等待狀態(tài)被喚醒時狭吼,期優(yōu)先級將有一點點提升,從而可以盡快獲得處理器的執(zhí)行權(至少比相同基本優(yōu)先級的其他線程優(yōu)先)
(3)16~31為實時優(yōu)先級殖妇,用于處理一些實時事務
線程的基本優(yōu)先級=[進程的基本優(yōu)先級 - 2刁笙,進程的基本優(yōu)先級 + 2],由應用程序控制拉一。線程的動態(tài)優(yōu)先級 = [ 進程的基本優(yōu)先級 - 2, 31]采盒,由NT 核心控制。為了提高調度速度蔚润,Windows NT維護了一個稱為就緒位圖的32位量磅氨。就緒位圖中的每一位指示一個調度優(yōu)先級的就緒隊列中是否有線程等待運行。還有一個稱為空閑位圖的32位量用來指示一個處理機是否處于空閑狀態(tài)嫡纠。
先來看看三個典型的線程調度算法:
(1)先到服務算法烦租。在非搶占式系統(tǒng)中,這一算法比較自然除盏,簡單來講叉橱,用一個FIFO隊列就可以滿足。所有的線程構成一個隊列者蠕,最先進入對嘞的線程獲得處理器的執(zhí)行權窃祝,得到放棄處理器的執(zhí)行權時,又回到隊列的隊尾踱侣,下一個線程繼續(xù)執(zhí)行粪小。若是在這個過程中有新的線程加入,將其添加到隊尾抡句。
(2)時間片輪轉調度算法探膊。處理器的時間被分為最大長度不超過牟哥值的時間片段,成為時間片待榔,然后用輪轉方法分配給每個線程逞壁。當一個線程獲得了處理器的執(zhí)行權之后,按照自身的邏輯執(zhí)行下去锐锣,知道時間片用完腌闯,或者自己主動放棄執(zhí)行權(比如要等待一個信號量)。系統(tǒng)在獲得處理器的控制權以后雕憔,用輪轉的方式找到下一個正在等待運行的線程姿骏,讓它繼續(xù)執(zhí)行。
(3)優(yōu)先級調度算法橘茉。在時間片輪轉算法中工腋,一個基本的假設是所有的線程都同等重要姨丈,這一假設在專用計算機上可能是非常合理的,但是擅腰,在現代多用途計算機上蟋恬,可能難以勝任多種不同類型的應用程序并發(fā)執(zhí)行的實際情形。優(yōu)先級調度算法是這種算法的一個改進趁冈,基本思路是歼争,每個線程都有一個優(yōu)先級值,高優(yōu)先級的線程總是優(yōu)先被考慮在處理器上執(zhí)行渗勘。操作系統(tǒng)在管理線程時沐绒,可以使用一個優(yōu)先級隊列,或者每個優(yōu)先級用一個隊列存放所有滿足執(zhí)行條件的線程旺坠。
對于上面提到的優(yōu)先級機制雖然可以實現調度乔遮,但光有線程的優(yōu)先級的話那么相同優(yōu)先級的線程中只有一個執(zhí)行到底,其他的都處于等待取刃,所以還有一個時間配額的制度蹋肮。時間配額是一個線程從進入運行狀態(tài)到系統(tǒng)檢查是否有其他優(yōu)先級相同的線程需要開始運行之間的時間總和。一個線程用完了自己的時間配額時璧疗,如果沒有其它相同優(yōu)先級線程坯辩,Windows 2000將重新給該線程分配一個新的時間配額,并繼續(xù)運行崩侠。每個線程都有一個代表本次運行最大時間長度的時間配額漆魔。
在每個線程擁有優(yōu)先級和時間配額后,通常線程先在許多等待函數的調用中進入等待狀態(tài)却音,進入等待狀態(tài)線程的時間配額不會被重置改抡,而是在等待事件出現時,線程的時間配額被減1相當于1/3個時鐘間隔僧家;如果線程的優(yōu)先級大于等于14在等待事件出現時雀摘,線程的優(yōu)先級被重置裸删“斯埃可能在這兩種情況下出現搶先的情況:一個是高優(yōu)先級線程的等待完成,即一個線程等待的事件出現涯塔。 一個是一個線程的優(yōu)先級被增加或減少肌稻。 在判斷一個線程是否被搶先時,并不考慮線程處于用戶態(tài)還是內核態(tài)匕荸,調度器只是依據線程優(yōu)先級進行判斷爹谭。 當線程被搶先時,它被放回相應優(yōu)先級的就緒隊列的隊首榛搔。 如果剛用完時間配額的線程優(yōu)先級降低了诺凡,系統(tǒng)將尋找一個優(yōu)先級高于剛用完時間配額線程的新設置值的就緒線程东揣。
如果剛用完時間配額的線程的優(yōu)先級沒有降低,并且有其他優(yōu)先級相同的就緒線程腹泌,系統(tǒng)將選擇相同優(yōu)先級的就緒隊列中的下一個線程進入運行狀態(tài)嘶卧,剛用完時間配額的線程被排到就緒隊列的隊尾(即分配一個新的時間配額并把線程狀態(tài)從運行狀態(tài)改為就緒狀態(tài))。 如果沒有優(yōu)先級相同的就緒線程可運行凉袱,剛用完時間配額的線程將得到一個新的時間配額并繼續(xù)運行芥吟。 當線程完成運行時,它的狀態(tài)從運行狀態(tài)轉到終止狀態(tài)专甩。線程完成運行的原因可能是通過調用函數而從主函數中返回或通過被其他線程通過調用函數來終止钟鸵。如果處于終止狀態(tài)的線程對象上沒有未關閉的句柄,則該線程將被從進程的線程列表中刪除涤躲,相關數據結構將被釋放棺耍。
對于線程的運行狀態(tài):每個線程從初始化開始到最后終止,其狀態(tài)會隨著系統(tǒng)的狀態(tài)以及它自身的代碼邏輯而發(fā)生變化种樱。Windows調度算法的線程狀態(tài)轉移圖比傳統(tǒng)的搶占式調度算法略微細致一些烈掠。本質上每個線程都處于兩種狀態(tài)之一:
(1)滿足繼續(xù)執(zhí)行的條件,整在排隊或者已經在執(zhí)行缸托。在這一情況中左敌,線程按照優(yōu)先級排隊執(zhí)行;對于多處理器系統(tǒng)俐镐,排隊的過程要復雜些矫限,調度器步進要處理多個隊列,而且要考慮每個處理器的就緒線程隊列的平衡程度佩抹。由于各個線程可能存在處理器親和性叼风,所以,此排隊和分發(fā)過程要略微復雜一些
(2)不滿足繼續(xù)執(zhí)行的條件棍苹,處于等待狀態(tài)无宿,或者它的調用棧甚至所處的進程被換出內存。在這一情況枢里,對于不滿足執(zhí)行條件的情形孽鸡,長期處于等待狀態(tài)的線程,其調用棧(設置整個進程)可能被換出內存栏豺,在這種情況下彬碱,一旦執(zhí)行條件已滿足,則要首先被換回內存奥洼,然后才能參與排隊分發(fā)
歸結我們得到大概的Windows線程基本調度機制是:線程優(yōu)先級制度+時間配額制度巷疼,來管理實現的
由于線程比進程開銷小而且創(chuàng)建得更快,同一進程內的多個線程共享同一塊內存灵奖,便于線程之間數據共享和傳送以及所有的進程資源對線程都有效的原因嚼沿,系統(tǒng)采用多線程而不采用多進程來實現多任務估盘。
首先一個處理器在一個時刻只能執(zhí)行一個線程,Windows NT允許用戶同時運行多個任務骡尽。這是通過下述方法實現的:
(1)運行一個線程,直到它被中斷或進入等待狀態(tài)忿檩;
(2)保存該線程的描述表;
(3)操作系統(tǒng)從等待執(zhí)行的線程隊列中挑選一個動態(tài)優(yōu)先級最高的線程作為執(zhí)行線程,裝入它的描述表(一旦線程獲得CPU時間片爆阶,它的動態(tài)優(yōu)先級就降低燥透,但不會低于它的基礎優(yōu)先級);
(4)若還存在等待被執(zhí)行的線程,則重復上述過程辨图。
處理器就是這樣根據優(yōu)先級不斷地切換執(zhí)行線程班套,它的高速度使人產生多個線程同時執(zhí)行的錯覺。所以一個處理器實際上仍然只能處理一個線程故河,這只是利用了高速度上的近似同時性吱韭。當計算機系統(tǒng)有多個處理器時,多線程就能實現真正的同時執(zhí)行鱼的。目前理盆,NT的對稱多處理器結構(SMP)最多支持32個處理器。
線程轉讓CPU處理時間是被迫的凑阶。占先式多任務可以防止線程獨占CPU,允許其它線程公平地分享CPU執(zhí)行時間,這和16位Windows環(huán)境下的協作式多任務有著本質的區(qū)別猿规。在16位Windows環(huán)境下,如果一個程序進入無限循環(huán),則其它應用程序可能永遠沒有機會執(zhí)行;而在Windows NT環(huán)境下這種情況不會發(fā)生,相反,許多線程的執(zhí)行部分都采用了循環(huán)掃描的結構。這也是實現了多線程的基礎宙橱。