淺談開發(fā)中的線程技術(shù)與線程模型

一汽绢、線程定義

什么是線程?《POSIX Threads Programming》中有一段話對線程的定義進行描述:

A thread is defined as an independent stream of instructions that can be scheduled to run as such by the operating system.

線程可以被認為是一個可以被獨立調(diào)度的實體佩谷,這個實體共享進程的地址空間百匆、文件描述符于微、代碼和數(shù)據(jù)暂衡,且擁有自己私有的棧、寄存器上下文浊服、和程序計數(shù)器统屈。

二、為什么要線程

我們在 github 上面給開源項目提交代碼的時候牙躺,按照 comment 格式都要寫 Motivation 這部分愁憔,我們今天討論線程這個存在,也要討論線程為什么存在孽拷。

在很多應(yīng)用中需要同時執(zhí)行多個任務(wù)吨掌,這些任務(wù)大部分甚至全部都可以相互獨立的并行的執(zhí)行。比如一個網(wǎng)絡(luò)代理乓搬,傳統(tǒng)的實現(xiàn)是用一個進程作為監(jiān)聽器來監(jiān)聽網(wǎng)絡(luò)端口思犁,當(dāng)有客戶端連接進來的時候代虾,當(dāng)前進程將會 fork 一個新的進程來處理客戶端的請求进肯。這種體系結(jié)構(gòu)不好的地方如下:

1、fork 系統(tǒng)調(diào)用對于操作系統(tǒng)來說是一個非常重的操作棉磨。
2江掩、每一個進程都有自己獨立的地址空間,進程間相互通信必須要通過標(biāo)準(zhǔn)的 IPC 技術(shù)來實現(xiàn),比如信號量环形、共享內(nèi)存策泣,這些操作是非常昂貴的、嚴重影響系統(tǒng)性能抬吟。

線程的出現(xiàn)就是為了解決這些問題萨咕,線程之間擁有共享的進程空間用于共享數(shù)據(jù)、也有自己獨立的運行空間類似一個輕量級的進程火本。

三危队、用戶空間與內(nèi)核空間

在理解用戶線程與內(nèi)核線程之前、我們有必要了解一下用戶空間與內(nèi)核空間「婆希現(xiàn)代操作系統(tǒng)的地址空間主要基于虛擬地址空間機制設(shè)計茫陆,和實際物理內(nèi)存大小沒關(guān)系,比如對于 32 位操作系統(tǒng)擎析,它的尋址空間為 2 的 32 次方也就是 4G簿盅,這里的尋址空間被稱為虛擬存儲空間。操作系統(tǒng)的核心是內(nèi)核揍魂,獨立于普通應(yīng)用程序桨醋,具有最高權(quán)限,可以訪問底層硬件設(shè)備以及受保護的空間愉烙,因此這部分包括驅(qū)動程序和操作系統(tǒng)讨盒。操作系統(tǒng)的設(shè)計者為了保證內(nèi)核的安全,將用戶進程設(shè)計為只有一定權(quán)限的程序步责,它不能夠操作內(nèi)核以及硬件返顺。操作系統(tǒng)將虛擬存儲空間劃分為兩部分,一部分是內(nèi)核空間蔓肯,一部分是用戶空間遂鹊。針對 Linux 操作系統(tǒng)而言,最高的 1G 字節(jié)供內(nèi)核使用蔗包,稱為內(nèi)核空間秉扑,較低的 3G 字節(jié)供給各個進程使用,被稱為用戶空間调限。進程可以通過系統(tǒng)調(diào)用進入內(nèi)核舟陆,Linux 內(nèi)核由所有進程共享。用戶空間和內(nèi)核空間示意圖如下:


用戶空間及內(nèi)核空間

四耻矮、用戶態(tài)與內(nèi)核態(tài)

每個進程都擁有所有的虛擬地址空間秦躯,當(dāng)進程運行用戶代碼的時候是運行在用戶地址空間的,這時候 CPU 運行所需要的指令和數(shù)據(jù)都保存在用戶空間裆装,進程可以認為是指令 + 數(shù)據(jù) + CPU踱承,因此這個時候我們把這個狀態(tài)的進程叫做用戶進程倡缠。當(dāng)用戶執(zhí)行系統(tǒng)調(diào)用而陷入內(nèi)核代碼中執(zhí)行的時候,當(dāng)前進程運行的指令和數(shù)據(jù)都在內(nèi)核空間茎活,因此我們把這個狀態(tài)的進程叫內(nèi)核進程昙沦。用戶進程和內(nèi)核進程不是獨立的兩個進程的意思,而是進程運行的不同狀態(tài)载荔。值得注意的是盾饮,用戶進程不能訪問內(nèi)核虛擬地址空間,內(nèi)核進程可以訪問全部的虛擬地址空間懒熙,因此用戶進程和內(nèi)核進程進行數(shù)據(jù)交換只能通過內(nèi)核進程從用戶地址空間取數(shù)據(jù)丐谋,然后放入用戶地址空間。

系統(tǒng)調(diào)用涉及到進程從用戶態(tài)到內(nèi)核態(tài)的切換(mode switch)煌珊,這個時候涉及到的切換主要是寄存器上下文的切換号俐,和通常所說的進程上下文切換不同,mode switch 的消耗相對要小很多定庵。

五吏饿、用戶線程與內(nèi)核線程

上面可以看出,用戶線程與內(nèi)核線程的區(qū)別主要在于指令與數(shù)據(jù)運行于不同虛擬地址空間蔬浙,用戶線程和內(nèi)核線程也可以叫做用戶空間線程和內(nèi)核空間線程猪落。用戶線程由用戶代碼支持,內(nèi)核線程由操作系統(tǒng)內(nèi)核支持畴博。

六笨忌、線程上下文切換

線程上下文切換和線程模態(tài)切換不是一個維度的東東,線程上下文切換講的是多線程之間因為調(diào)度器的調(diào)度俱病,而從一個線程正在被調(diào)度切換到另外一個線程被調(diào)度的事情官疲。線程上下文切換必須要保存線程執(zhí)行的寄存器狀態(tài)、棧信息亮隙、線程正文途凫、數(shù)據(jù)等,因此相對模態(tài)切換是比較重的操作溢吻。

七维费、線程模型

線程模型在不同的操作系統(tǒng)下的實現(xiàn)通常有三種,每種模型都有其優(yōu)點與缺點促王,下面我們來看看這三種線程模型犀盟。

1、用戶空間線程模型(M : 1)

一個多線程子系統(tǒng)有可能全部由用戶代碼實現(xiàn)蝇狼,這些線程的調(diào)度與切換全部發(fā)生在用戶地址空間阅畴,這種模型通常是由一個內(nèi)核線程和多個用戶線程組成。典型的實現(xiàn)是基于 POSIX 線程 draft 4题翰,OSF’DCE 是其中一種具體實現(xiàn)恶阴。一個用戶空間庫負責(zé)線程的創(chuàng)建、終止豹障、調(diào)度與同步冯事。這些線程對于操作系統(tǒng)內(nèi)核是透明的。

這種模型的好處是線程上下文切換都發(fā)生在用戶空間血公,避免的模態(tài)切換(mode switch)昵仅,從而對于性能有積極的影響。然而不好的地方是所有的線程基于一個內(nèi)核調(diào)度實體即內(nèi)核線程累魔,這意味著只有一個處理器可以被利用摔笤,在多處理環(huán)境下這是不能夠被接受的,本質(zhì)上垦写,用戶線程只解決了并發(fā)問題吕世,但是沒有解決并行問題。

還有一點梯投,如果線程因為 I/O 操作陷入了內(nèi)核態(tài)命辖,內(nèi)核態(tài)線程阻塞等待 I/O 數(shù)據(jù),則所有的線程都將會被阻塞分蓖,用戶空間也可以使用非阻塞而 I/O尔艇,但是還是有性能及復(fù)雜度問題。


用戶空間線程模型
2么鹤、內(nèi)核空間線程模型(1:1)

對于用戶空間線程模型终娃,所有的用戶線程都和特定的內(nèi)核線程進行交互,而內(nèi)核空間線程模型是每個用戶線程都和一個特定的內(nèi)核線程進行交互蒸甜,用戶線程和內(nèi)核線程是 1:1 的關(guān)系棠耕。典型的實現(xiàn)是將每個用戶線程映射到一個內(nèi)核線程上。

每個線程由內(nèi)核調(diào)度器獨立的調(diào)度柠新,所以如果一個線程阻塞則不影響其他的線程昧辽。然而,創(chuàng)建登颓、終止和同步線程都會發(fā)生在內(nèi)核地址空間搅荞,這可能會帶來較大的性能問題。在創(chuàng)建線程的時候內(nèi)核必須要進行內(nèi)存鎖的申請框咙,并負責(zé)調(diào)度線程咕痛,而且每個線程都要消耗有限的內(nèi)核資源,當(dāng)大量的線程被創(chuàng)建的時候喇嘱,體現(xiàn)的尤為明顯茉贡。值得夸獎的是,在多核處理器的硬件的支持下者铜,內(nèi)核空間線程模型支持了真正的并行腔丧,下面是內(nèi)核空間模型示意圖:


內(nèi)核空間線程模型
3放椰、內(nèi)核用戶空間線程模型(M : N)

內(nèi)核用戶空間線程模型中,內(nèi)核線程和用戶線程的數(shù)量比為 M : N愉粤,因此也通常被叫做 M : N 線程模型砾医,內(nèi)核用戶空間綜合了前兩種的優(yōu)點。

這種模型需要內(nèi)核線程調(diào)度器和用戶空間線程調(diào)度器相互操作衣厘,本質(zhì)上是多個線程被綁定到了多個內(nèi)核線程上如蚜,這使得大部分的線程上下文切換都發(fā)生在用戶空間,而多個內(nèi)核線程又可以充分利用處理器資源影暴,模型圖如下:


內(nèi)核用戶空間線程模型

總結(jié)

最近在深入學(xué)習(xí)多線程的時候错邦,大量學(xué)習(xí)了網(wǎng)上很多大神發(fā)表的文章,總結(jié)成上面的文章型宙,歡迎大家指正撬呢。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市妆兑,隨后出現(xiàn)的幾起案子倾芝,更是在濱河造成了極大的恐慌,老刑警劉巖箭跳,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晨另,死亡現(xiàn)場離奇詭異,居然都是意外死亡谱姓,警方通過查閱死者的電腦和手機借尿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屉来,“玉大人路翻,你說我怎么就攤上這事∏芽浚” “怎么了茂契?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長慨绳。 經(jīng)常有香客問我掉冶,道長,這世上最難降的妖魔是什么脐雪? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任厌小,我火速辦了婚禮,結(jié)果婚禮上战秋,老公的妹妹穿的比我還像新娘璧亚。我一直安慰自己,他們只是感情好脂信,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布癣蟋。 她就那樣靜靜地躺著透硝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪疯搅。 梳的紋絲不亂的頭發(fā)上濒生,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音秉撇,去河邊找鬼。 笑死秋泄,一個胖子當(dāng)著我的面吹牛琐馆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恒序,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瘦麸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了歧胁?” 一聲冷哼從身側(cè)響起滋饲,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎喊巍,沒想到半個月后屠缭,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡崭参,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年呵曹,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片何暮。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡奄喂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出海洼,到底是詐尸還是另有隱情跨新,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布坏逢,位于F島的核電站域帐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏是整。R本人自食惡果不足惜俯树,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贰盗。 院中可真熱鬧许饿,春花似錦、人聲如沸舵盈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瓦糟,卻和暖如春筒愚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背菩浙。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工巢掺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人劲蜻。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓陆淀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親先嬉。 傳聞我的和親對象是個殘疾皇子轧苫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容