原文:https://blog.csdn.net/gatieme/article/details/51481863
線程與進(jìn)程概念
在現(xiàn)代操作系統(tǒng)中拘悦,進(jìn)程支持多線程。
進(jìn)程是資源管理的最小單元橱脸;
線程是程序執(zhí)行的最小單元础米。
即線程作為調(diào)度和分配的基本單位,進(jìn)程作為資源分配的基本單位
一個(gè)進(jìn)程的組成實(shí)體可以分為兩大部分:線程集和資源集添诉。進(jìn)程中的線程是動(dòng)態(tài)的對(duì)象屁桑;代表了進(jìn)程指令的執(zhí)行。資源栏赴,包括地址空間蘑斧、打開的文件、用戶信息等等艾帐,由進(jìn)程內(nèi)的線程共享乌叶。
線程概念的產(chǎn)生
傳統(tǒng)單線程進(jìn)程的缺點(diǎn)
現(xiàn)實(shí)中有很多需要并發(fā)處理的任務(wù),如數(shù)據(jù)庫的服務(wù)器端柒爸、網(wǎng)絡(luò)服務(wù)器准浴、大容量計(jì)算等。
傳統(tǒng)的UNIX進(jìn)程是單線程的捎稚,單線程意味著程序必須是順序執(zhí)行乐横,不能并發(fā);既在一個(gè)時(shí)刻只能運(yùn)行在一個(gè)處理器上今野,因此不能充分利用多處理器框架的計(jì)算機(jī)葡公。
-
如果采用多進(jìn)程的方法,則有如下問題:
- fork一個(gè)子進(jìn)程的消耗是很大的条霜,fork是一個(gè)昂貴的系統(tǒng)調(diào)用催什,即使使用現(xiàn)代的寫時(shí)復(fù)制(copy-on-write)技術(shù)。
- 各個(gè)進(jìn)程擁有自己獨(dú)立的地址空間宰睡,進(jìn)程間的協(xié)作需要復(fù)雜的IPC技術(shù)蒲凶,如消息傳遞和共享內(nèi)存等气筋。
多線程的優(yōu)缺點(diǎn)
多線程的優(yōu)點(diǎn)和缺點(diǎn)實(shí)際上是對(duì)立統(tǒng)一的。
支持多線程的程序(進(jìn)程)可以取得真正的并行(parallelism)旋圆,且由于共享進(jìn)程的代碼和全局?jǐn)?shù)據(jù)宠默,故線程間的通信是方便的。它的缺點(diǎn)也是由于線程共享進(jìn)程的地址空間灵巧,因此可能會(huì)導(dǎo)致競爭搀矫,因此對(duì)某一塊有多個(gè)線程要訪問的數(shù)據(jù)需要一些同步技術(shù)。
線程的設(shè)計(jì)過程演變
在操作系統(tǒng)設(shè)計(jì)上刻肄,從進(jìn)程演化出線程瓤球,最主要的目的就是更好的支持SMP以及減小(進(jìn)程/線程)上下文切換開銷敏弃。
SMP機(jī)器上多線程的并行性
無論按照怎樣的分法冰垄,一個(gè)進(jìn)程至少需要一個(gè)線程作為它的指令執(zhí)行體,進(jìn)程管理著資源(比如cpu权她、內(nèi)存、文件等等)逝薪,而將線程分配到某個(gè)cpu上執(zhí) 行隅要。
一個(gè)進(jìn)程當(dāng)然可以擁有多個(gè)線程,此時(shí)董济,如果進(jìn)程運(yùn)行在SMP機(jī)器上步清,它就可以同時(shí)使用多個(gè)cpu來執(zhí)行各個(gè)線程,達(dá)到最大程度的并行虏肾,以提高效率廓啊;同 時(shí),即使是在單cpu的機(jī)器上封豪,采用多線程模型來設(shè)計(jì)程序谴轮,正如當(dāng)年采用多進(jìn)程模型代替單進(jìn)程模型一樣,使設(shè)計(jì)更簡潔吹埠、功能更完備第步,程序的執(zhí)行效率也更 高,例如采用多個(gè)線程響應(yīng)多個(gè)輸入缘琅,而此時(shí)多線程模型所實(shí)現(xiàn)的功能實(shí)際上也可以用多進(jìn)程模型來實(shí)現(xiàn)粘都,而與后者相比,線程的上下文切換開銷就比進(jìn)程要小多 了刷袍,從語義上來說翩隧,同時(shí)響應(yīng)多個(gè)輸入這樣的功能,實(shí)際上就是共享了除cpu以外的所有資源的呻纹。
線程模型–核心級(jí)線程和用戶級(jí)線程
針對(duì)線程模型的兩大意義堆生,分別開發(fā)出了核心級(jí)線程和用戶級(jí)線程兩種線程模型专缠,分類的標(biāo)準(zhǔn)主要是線程的調(diào)度者在核內(nèi)還是在核外。前者更利于并發(fā)使用多處理器的資源顽频,而后者則更多考慮的是上下文切換開銷藤肢。
關(guān)于線程的實(shí)現(xiàn)模型,可以參見博主的另外一篇博客線程的3種實(shí)現(xiàn)方式–內(nèi)核級(jí)線程, 用戶級(jí)線程和混合型線程
目前的實(shí)現(xiàn)策略
在目前的商用系統(tǒng)中,通常都將兩者結(jié)合起來使用糯景,既提供核心線程以滿足smp系統(tǒng)的需要嘁圈,也支持用線 程庫的方式在用戶態(tài)實(shí)現(xiàn)另一套線程機(jī)制,此時(shí)一個(gè)核心線程同時(shí)成為多個(gè)用戶態(tài)線程的調(diào)度者蟀淮。
正如很多技術(shù)一樣最住,”混合”通常都能帶來更高的效率,但同時(shí)也 帶來更大的實(shí)現(xiàn)難度怠惶,出于”簡單”的設(shè)計(jì)思路涨缚,Linux從一開始就沒有實(shí)現(xiàn)混合模型的計(jì)劃,但它在實(shí)現(xiàn)上采用了另一種思路的”混合”策治。
在線程機(jī)制的具體實(shí)現(xiàn)上脓魏,可以在操作系統(tǒng)內(nèi)核上實(shí)現(xiàn)線程,也可以在核外實(shí)現(xiàn)通惫,后者顯然要求核內(nèi)至少實(shí)現(xiàn)了進(jìn)程茂翔,而前者則一般要求在核內(nèi)同時(shí)也支持進(jìn) 程。核心級(jí)線程模型顯然要求前者的支持履腋,而用戶級(jí)線程模型則不一定基于后者實(shí)現(xiàn)珊燎。這種差異,正如前所述遵湖,是兩種分類方式的標(biāo)準(zhǔn)不同帶來的悔政。
當(dāng)核內(nèi)既支持進(jìn)程也支持線程時(shí),就可以實(shí)現(xiàn)線程-進(jìn)程的”多對(duì)多”模型延旧,即一個(gè)進(jìn)程的某個(gè)線程由核內(nèi)調(diào)度谋国,而同時(shí)它也可以作為用戶級(jí)線程池的調(diào)度 者,選擇合適的用戶級(jí)線程在其空間中運(yùn)行迁沫。這就是前面提到的”混合”線程模型烹卒,既可滿足多處理機(jī)系統(tǒng)的需要,也可以最大限度的減小調(diào)度開銷弯洗。
絕大多數(shù)商業(yè) 操作系統(tǒng)(如Digital Unix旅急、Solaris、Irix)都采用的這種能夠完全實(shí)現(xiàn)POSIX1003.1c標(biāo)準(zhǔn)的線程模型牡整。在核外實(shí)現(xiàn)的線程又可以分為”一對(duì)一”藐吮、”多對(duì) 一”兩種模型,前者用一個(gè)核心進(jìn)程(也許是輕量進(jìn)程)對(duì)應(yīng)一個(gè)線程,將線程調(diào)度等同于進(jìn)程調(diào)度谣辞,交給核心完成迫摔,而后者則完全在核外實(shí)現(xiàn)多線程,調(diào)度也在用 戶態(tài)完成泥从。后者就是前面提到的單純的用戶級(jí)線程模型的實(shí)現(xiàn)方式句占,顯然,這種核外的線程調(diào)度器實(shí)際上只需要完成線程運(yùn)行棧的切換躯嫉,調(diào)度開銷非常小纱烘,但同時(shí)因 為核心信號(hào)(無論是同步的還是異步的)都是以進(jìn)程為單位的,因而無法定位到線程祈餐,所以這種實(shí)現(xiàn)方式不能用于多處理器系統(tǒng)擂啥,而這個(gè)需求正變得越來越大,因 此帆阳,在現(xiàn)實(shí)中哺壶,純用戶級(jí)線程的實(shí)現(xiàn),除算法研究目的以外蜒谤,幾乎已經(jīng)消失了山宾。
Linux內(nèi)核只提供了輕量進(jìn)程的支持,限制了更高效的線程模型的實(shí)現(xiàn)鳍徽,但Linux著重優(yōu)化了進(jìn)程的調(diào)度開銷塌碌,一定程度上也彌補(bǔ)了這一缺陷。目前 最流行的線程機(jī)制LinuxThreads所采用的就是線程-進(jìn)程”一對(duì)一”模型旬盯,調(diào)度交給核心,而在用戶級(jí)實(shí)現(xiàn)一個(gè)包括信號(hào)處理在內(nèi)的線程管理機(jī)制翎猛。
三種線程概念——內(nèi)核線程胖翰、輕量級(jí)進(jìn)程、用戶線程
內(nèi)核線程
內(nèi)核線程就是內(nèi)核的分身切厘,一個(gè)分身可以處理一件特定事情。這在處理異步事件如異步IO時(shí)特別有用。內(nèi)核線程的使用是廉價(jià)的达吞,唯一使用的資源就是內(nèi)核棧和上下文切換時(shí)保存寄存器的空間粉臊。支持多線程的內(nèi)核叫做多線程內(nèi)核(Multi-Threads kernel )。
內(nèi)核線程只運(yùn)行在內(nèi)核態(tài)遗座,不受用戶態(tài)上下文的拖累舀凛。
處理器競爭:可以在全系統(tǒng)范圍內(nèi)競爭處理器資源;
使用資源:唯一使用的資源是內(nèi)核棧和上下文切換時(shí)保持寄存器的空間
調(diào)度:調(diào)度的開銷可能和進(jìn)程自身差不多昂貴
同步效率:資源的同步和數(shù)據(jù)共享比整個(gè)進(jìn)程的數(shù)據(jù)同步和共享要低一些途蒋。
輕量級(jí)進(jìn)程
輕量級(jí)進(jìn)程(LWP)是建立在內(nèi)核之上并由內(nèi)核支持的用戶線程猛遍,它是內(nèi)核線程的高度抽象,每一個(gè)輕量級(jí)進(jìn)程都與一個(gè)特定的內(nèi)核線程關(guān)聯(lián)。內(nèi)核線程只能由內(nèi)核管理并像普通進(jìn)程一樣被調(diào)度懊烤。
a LWP runs in user space on top of a single kernel thread and shares its address space and system resources with other LWPs within the same process
輕量級(jí)進(jìn)程由clone()系統(tǒng)調(diào)用創(chuàng)建梯醒,參數(shù)是CLONE_VM,即與父進(jìn)程是共享進(jìn)程地址空間和系統(tǒng)資源腌紧。
與普通進(jìn)程區(qū)別:LWP只有一個(gè)最小的執(zhí)行上下文和調(diào)度程序所需的統(tǒng)計(jì)信息茸习。
處理器競爭:因與特定內(nèi)核線程關(guān)聯(lián),因此可以在全系統(tǒng)范圍內(nèi)競爭處理器資源
使用資源:與父進(jìn)程共享進(jìn)程地址空間
調(diào)度:像普通進(jìn)程一樣調(diào)度
輕量級(jí)線程(LWP)是一種由內(nèi)核支持的用戶線程壁肋。它是基于內(nèi)核線程的高級(jí)抽象号胚,因此只有先支持內(nèi)核線程,才能有LWP墩划。每一個(gè)進(jìn)程有一個(gè)或多個(gè)LWPs涕刚,每個(gè)LWP由一個(gè)內(nèi)核線程支持。這種模型實(shí)際上就是恐龍書上所提到的一對(duì)一線程模型乙帮。在這種實(shí)現(xiàn)的操作系統(tǒng)中杜漠,LWP就是用戶線程。
由于每個(gè)LWP都與一個(gè)特定的內(nèi)核線程關(guān)聯(lián)察净,因此每個(gè)LWP都是一個(gè)獨(dú)立的線程調(diào)度單元驾茴。即使有一個(gè)LWP在系統(tǒng)調(diào)用中阻塞,也不會(huì)影響整個(gè)進(jìn)程的執(zhí)行氢卡。
輕量級(jí)進(jìn)程具有局限性锈至。
首先,大多數(shù)LWP的操作译秦,如建立峡捡、析構(gòu)以及同步,都需要進(jìn)行系統(tǒng)調(diào)用筑悴。系統(tǒng)調(diào)用的代價(jià)相對(duì)較高:需要在user mode和kernel mode中切換们拙。
其次,每個(gè)LWP都需要有一個(gè)內(nèi)核線程支持阁吝,因此LWP要消耗內(nèi)核資源(內(nèi)核線程的椦馄牛空間)。因此一個(gè)系統(tǒng)不能支持大量的LWP突勇。
注:
- LWP的術(shù)語是借自于SVR4/MP和Solaris 2.x装盯。
- 有些系統(tǒng)將LWP稱為虛擬處理器。
- 將之稱為輕量級(jí)進(jìn)程的原因可能是:在內(nèi)核線程的支持下甲馋,LWP是獨(dú)立的調(diào)度單元埂奈,就像普通的進(jìn)程一樣。所以LWP的最大特點(diǎn)還是每個(gè)LWP都有一個(gè)內(nèi)核線程支持定躏。
用戶線程
用戶線程是完全建立在用戶空間的線程庫挥转,用戶線程的創(chuàng)建海蔽、調(diào)度、同步和銷毀全又庫函數(shù)在用戶空間完成绑谣,不需要內(nèi)核的幫助党窜。因此這種線程是極其低消耗和高效的。
處理器競爭:單純的用戶線程是建立在用戶空間借宵,其對(duì)內(nèi)核是透明的幌衣,因此其所屬進(jìn)程單獨(dú)參與處理器的競爭,而進(jìn)程的所有線程參與競爭該進(jìn)程的資源壤玫。
使用資源:與所屬進(jìn)程共享進(jìn)程地址空間和系統(tǒng)資源豁护。
調(diào)度:由在用戶空間實(shí)現(xiàn)的線程庫,在所屬進(jìn)程內(nèi)進(jìn)行調(diào)度
LWP雖然本質(zhì)上屬于用戶線程欲间,但LWP線程庫是建立在內(nèi)核之上的楚里,LWP的許多操作都要進(jìn)行系統(tǒng)調(diào)用,因此效率不高猎贴。而這里的用戶線程指的是完全建立在用戶空間的線程庫班缎,用戶線程的建立,同步她渴,銷毀达址,調(diào)度完全在用戶空間完成,不需要內(nèi)核的幫助趁耗。因此這種線程的操作是極其快速的且低消耗的沉唠。
上圖是最初的一個(gè)用戶線程模型,從中可以看出苛败,進(jìn)程中包含線程满葛,用戶線程在用戶空間中實(shí)現(xiàn),內(nèi)核并沒有直接對(duì)用戶線程進(jìn)程調(diào)度罢屈,內(nèi)核的調(diào)度對(duì)象和傳統(tǒng)進(jìn)程一樣嘀韧,還是進(jìn)程本身,內(nèi)核并不知道用戶線程的存在儡遮。
用戶線程之間的調(diào)度由在用戶空間實(shí)現(xiàn)的線程庫實(shí)現(xiàn)。
這種模型對(duì)應(yīng)著恐龍書中提到的多對(duì)一線程模型暗赶,其缺點(diǎn)是一個(gè)用戶線程如果阻塞在系統(tǒng)調(diào)用中鄙币,則整個(gè)進(jìn)程都將會(huì)阻塞。
加強(qiáng)版的用戶線程——用戶線程+LWP
這種模型對(duì)應(yīng)著恐龍書中多對(duì)多模型蹂随。
用戶線程庫還是完全建立在用戶空間中十嘿,因此用戶線程的操作還是很廉價(jià),因此可以建立任意多需要的用戶線程岳锁。
操作系統(tǒng)提供了LWP作為用戶線程和內(nèi)核線程之間的橋梁绩衷。LWP還是和前面提到的一樣,具有內(nèi)核線程支持,是內(nèi)核的調(diào)度單元咳燕,并且用戶線程的系統(tǒng)調(diào)用要通過LWP勿决,因此進(jìn)程中某個(gè)用戶線程的阻塞不會(huì)影響整個(gè)進(jìn)程的執(zhí)行。
用戶線程庫將建立的用戶線程關(guān)聯(lián)到LWP上招盲,LWP與用戶線程的數(shù)量不一定一致低缩。當(dāng)內(nèi)核調(diào)度到某個(gè)LWP上時(shí),此時(shí)與該LWP關(guān)聯(lián)的用戶線程就被執(zhí)行曹货。
Linux使用的線程庫
LinuxThreads是用戶空間的線程庫咆繁,所采用的是線程-進(jìn)程1對(duì)1模型(即一個(gè)用戶線程對(duì)應(yīng)一個(gè)輕量級(jí)進(jìn)程,而一個(gè)輕量級(jí)進(jìn)程對(duì)應(yīng)一個(gè)特定的內(nèi)核線程)顶籽,將線程的調(diào)度等同于進(jìn)程的調(diào)度玩般,調(diào)度交由內(nèi)核完成,而線程的創(chuàng)建礼饱、同步坏为、銷毀由核外線程庫完成(LinuxThtreads已綁定到 GLIBC中發(fā)行)。
在LinuxThreads中慨仿,由專門的一個(gè)管理線程處理所有的線程管理工作久脯。當(dāng)進(jìn)程第一次調(diào)用pthread_create()創(chuàng)建線程時(shí)就會(huì)先 創(chuàng)建(clone())并啟動(dòng)管理線程。后續(xù)進(jìn)程pthread_create()創(chuàng)建線程時(shí)镰吆,都是管理線程作為pthread_create()的調(diào)用者的子線程帘撰,通過調(diào)用clone()來創(chuàng)建用戶線程,并記錄輕量級(jí)進(jìn)程號(hào)和線程id的映射關(guān)系万皿,因此摧找,用戶線程其實(shí)是管理線程的子線程。
LinuxThreads只支持調(diào)度范圍為PTHREAD_SCOPE_SYSTEM的調(diào)度牢硅,默認(rèn)的調(diào)度策略是SCHED_OTHER蹬耘。
用戶線程調(diào)度策略也可修改成SCHED_FIFO或SCHED_RR方式,這兩種方式支持優(yōu)先級(jí)為0-99,而SCHED_OTHER只支持0减余。
SCHED_OTHER 分時(shí)調(diào)度策略综苔,
SCHED_FIFO 實(shí)時(shí)調(diào)度策略,先到先服務(wù)
SCHED_RR 實(shí)時(shí)調(diào)度策略位岔,時(shí)間片輪轉(zhuǎn)
SCHED_OTHER是普通進(jìn)程的如筛,后兩個(gè)是實(shí)時(shí)進(jìn)程的(一般的進(jìn)程都是普通進(jìn)程,系統(tǒng)中出現(xiàn)實(shí)時(shí)進(jìn)程的機(jī)會(huì)很少)抒抬。SCHED_FIFO杨刨、 SCHED_RR優(yōu)先級(jí)高于所有SCHED_OTHER的進(jìn)程,所以只要他們能夠運(yùn)行擦剑,在他們運(yùn)行完之前妖胀,所有SCHED_OTHER的進(jìn)程的都沒有得到 執(zhí)行的機(jī)會(huì)
小結(jié):
很多文獻(xiàn)中都認(rèn)為輕量級(jí)進(jìn)程就是線程芥颈,實(shí)際上這種說法并不完全正確,從前面的分析中可以看到赚抡,只有在用戶線程完全由輕量級(jí)進(jìn)程構(gòu)成時(shí)爬坑,才可以說輕量級(jí)進(jìn)程就是線程。