本文從linux中的進程诵原、線程實現(xiàn)原理開始鞭莽,擴展到linux線程模型,最后簡單解釋線程切換的成本费尽。
剛開始學習仅父,不一定對叛薯,好心人們快來指正我啊啊啊s舷恕:牧铩!
linux中的進程與線程
首先明確進程與進程的基本概念:
- 進程是資源分配的基本單位
- 線程是CPU調(diào)度的基本單位
- 一個進程下可能有多個線程
- 線程共享進程的資源
基本原理
linux用戶態(tài)的進程省容、線程基本滿足上述概念抖拴,但內(nèi)核態(tài)不區(qū)分進程和線程⌒冉罚可以認為阿宅,內(nèi)核中統(tǒng)一執(zhí)行的是進程,但有些是“普通進程”(對應(yīng)進程process)笼蛛,有些是“輕量級進程”(對應(yīng)線程pthread或npthread)洒放,都使用task_struct
結(jié)構(gòu)體保存保存。
使用fork
創(chuàng)建進程伐弹,使用pthread_create
創(chuàng)建線程拉馋。兩個系統(tǒng)調(diào)用最終都都調(diào)用了do_dork
,而do_dork
完成了task_struct
結(jié)構(gòu)體的復制惨好,并將新的進程加入內(nèi)核調(diào)度煌茴。
進程是資源分配的基本單位、線程共享進程的資源
普通進程需要深拷貝虛擬內(nèi)存日川、文件描述符蔓腐、信號處理等;而輕量級進程之所以“輕量”龄句,是因為其只需要淺拷貝虛擬內(nèi)存等大部分信息回论,多個輕量級進程共享一個進程的資源。
線程是CPU調(diào)度的基本單位分歇、一個進程下可能有多個線程
linux加入了線程組的概念傀蓉,讓原有“進程”對應(yīng)線程,“線程組”對應(yīng)進程职抡,實現(xiàn)“一個進程下可能有多個線程”:
- 操作系統(tǒng)中存在多個進程組
- 一個進程組下有多個進程(1:n)
- 一個進程對應(yīng)一個線程組(1:1)
- 一個線程組下有多個線程(1:n)
task_struct
中葬燎,使用pgid標的進程組,tgid標的線程組,pid標的進程或線程谱净。假設(shè)目前有一個進程組窑邦,則上述概念對應(yīng)如下:
- 進程組中有一個主進程(父進程),pid等于進程組的pgid壕探;進程組下的其他進程都是父進程的子進程冈钦,pid不等于pgid
- 每個進程對應(yīng)一個線程組,pid等于tgid李请。
- 線程組中有一個“主線程”(勉強稱為“主線程”瞧筛,位的是與主進程對應(yīng);語義上絕不能稱為“父線程”)捻艳,pid等于該線程組的tgid驾窟;線程組下的其他線程都是與主線程平級,pid不等于tgid
因此认轨,調(diào)用getpgid返回pgid绅络,調(diào)用getpid應(yīng)返回tgid,調(diào)用gettid應(yīng)返回pid嘁字。使用的時候不要糊涂恩急。
進程下除主線程外的其他線程是CPU調(diào)度的基本單位,這很好理解纪蜒。而所謂主線程與所屬進程實際上是同一個task_struct
衷恭,也能被CPU調(diào)度,因此主線程也是CPU調(diào)度的基本單位纯续。
tgid相同的所有線程組成了概念上的“進程”随珠,只有主線程在創(chuàng)建時會實際分配資源,其他線程通過淺拷貝共享主線程的資源猬错。結(jié)合前面介紹的普通線程與輕量級進程窗看,實現(xiàn)“進程是資源分配的基本單位”。
舉個栗子
pgid | tgid | pid |
---|---|---|
111 | 111 | 111 |
112 | 112 | 112 |
112 | 112 | 113 |
113 | 113 | 113 |
113 | 113 | 114 |
113 | 115 | 115 |
113 | 115 | 116 |
113 | 115 | 117 |
- 存在3個進程組111倦炒、112显沈、113
- 進程組111下有1個父進程111,單獨分配資源
- 進程111下有1個線程111逢唤,共享進程111的資源
- 進程組112下有1個父進程112拉讯,單獨分配資源
- 進程112下有2個線程112、113鳖藕,共享進程112的資源
- 進程組113下有1個父進程113魔慷,1個子進程115,各自單獨分配資源
- 進程113下有2個線程113著恩、114院尔,共享進程113的資源
- 進程115下有3個線程115纹烹、116、117召边,共享進程115的資源
- 進程組111下有1個父進程111,單獨分配資源
小結(jié)
現(xiàn)在再來理解linux中的進程與線程就容易多了:
- 進程是一個邏輯上的概念,用于管理資源裹驰,對應(yīng)
task_struct
中的資源 - 每個進程至少有一個線程隧熙,用于具體的執(zhí)行,對應(yīng)
task_struct
中的任務(wù)調(diào)度信息 - 以
task_struct
中的pid區(qū)分線程幻林,tgid區(qū)分進程贞盯,pgid區(qū)分進程組
linux線程模型
一對一
LinuxThreads與NPTL均采用一對一
的線程模型,一個用戶線程對應(yīng)一個內(nèi)核線程沪饺。內(nèi)核負責每個線程的調(diào)度躏敢,可以調(diào)度到其他處理器上面。Linux 2.6默認使用NPTL線程庫整葡,一對一的線程模型件余。
優(yōu)點:
- 實現(xiàn)簡單。
缺點:
- 對用戶線程的大部分操作都會映射到內(nèi)核線程上遭居,引起用戶態(tài)和內(nèi)核態(tài)的頻繁切換啼器。
- 內(nèi)核為每個線程都映射調(diào)度實體,如果系統(tǒng)出現(xiàn)大量線程俱萍,會對系統(tǒng)性能有影響端壳。
多對一
顧名思義,多對一
線程模型中枪蘑,多個用戶線程對應(yīng)到同一個內(nèi)核線程上损谦,線程的創(chuàng)建、調(diào)度岳颇、同步的所有細節(jié)全部由進程的用戶空間線程庫來處理照捡。
優(yōu)點:
- 用戶線程的很多操作對內(nèi)核來說都是透明的,不需要用戶態(tài)和內(nèi)核態(tài)的頻繁切換赦役。使線程的創(chuàng)建麻敌、調(diào)度、同步等非车嗨ぃ快术羔。
缺點:
- 由于多個用戶線程對應(yīng)到同一個內(nèi)核線程,如果其中一個用戶線程阻塞乙漓,那么該其他用戶線程也無法執(zhí)行级历。
- 內(nèi)核并不知道用戶態(tài)有哪些線程,無法像內(nèi)核線程一樣實現(xiàn)較完整的調(diào)度叭披、優(yōu)先級等
多對多
多對一線程模型是非常輕量的寥殖,問題在于多個用戶線程對應(yīng)到固定的一個內(nèi)核線程玩讳。多對多線程模型解決了這一問題:m個用戶線程對應(yīng)到n個內(nèi)核線程上,通常m>n
嚼贡。由IBM主導的NGPT采用了多對多
的線程模型熏纯,不過現(xiàn)在已廢棄。
優(yōu)點:
- 兼具多對一模型的輕量
- 由于對應(yīng)了多個內(nèi)核線程粤策,則一個用戶線程阻塞時樟澜,其他用戶線程仍然可以執(zhí)行
- 由于對應(yīng)了多個內(nèi)核線程,則可以實現(xiàn)較完整的調(diào)度叮盘、優(yōu)先級等
缺點:
- 實現(xiàn)復雜
線程切換
linux采用一對一的線程模型秩贰,用戶線程切換與內(nèi)核線程切換之間的差別非常小。同時柔吼,如果忽略用戶主動放棄用戶線程的執(zhí)行權(quán)(yield)帶來的開銷毒费,則只需要考慮內(nèi)核線程切換的開銷。
注意愈魏,這里僅僅是為了幫助理解做出的簡化觅玻。實際上,用戶線程庫在用戶線程的調(diào)度蝌戒、同步等過程中做了很多工作串塑,這部分開銷不能忽略。
如JVM對Thread#yield()的解釋:如果底層OS不支持yield的語義北苟,則JVM讓用戶線程自旋至時間片結(jié)束桩匪,線程被動切換,以達到相似的效果友鼻。
什么引起線程切換
- 時間片輪轉(zhuǎn)
- 線程阻塞
- 線程主動放棄時間片
線程切換的開銷
直接開銷
直接開銷是線程切換本身引起的傻昙,無可避免,必然發(fā)生彩扔。
用戶態(tài)與內(nèi)核態(tài)的切換
線程切換只能在內(nèi)核態(tài)完成妆档,如果當前用戶處于用戶態(tài),則必然引起用戶態(tài)與內(nèi)核態(tài)的切換虫碉。(<font color="red">“用戶態(tài)與內(nèi)核態(tài)的切換”具體帶來什么成本贾惦??敦捧?</font>)
上下文切換
前面說線程(或者叫做進程都隨意)信息需要用一個task_struct
保存须板,線程切換時,必然需要將舊線程的task_struct
從內(nèi)核切出兢卵,將新線程的切入习瑰,帶來上下文切換。除此之外秽荤,還需要切換寄存器甜奄、程序計數(shù)器柠横、線程棧(包括操作棧、數(shù)據(jù)棧)等课兄。
線程調(diào)度算法
線程調(diào)度算法需要管理線程的狀態(tài)牍氛、等待條件等,如果根據(jù)優(yōu)先級調(diào)度烟阐,則還需要維護優(yōu)先級隊列糜俗。如果線程切換比較頻繁,該成本不容小覷曲饱。
間接開銷
間接開銷是直接開銷的副作用,取決于系統(tǒng)實現(xiàn)和用戶代碼實現(xiàn)珠月。
緩存缺失
切換進程扩淀,需要執(zhí)行新邏輯。如果二者的訪問的地址空間不相近啤挎,則會引起緩存缺失驻谆,具體影響范圍取決于系統(tǒng)實現(xiàn)和用戶代碼實現(xiàn)。如果系統(tǒng)的緩存較大庆聘,則能減小緩存缺失的影響胜臊;如果用戶線程訪問數(shù)據(jù)的地址空間接近,則本身的緩存缺失率也比較低伙判。
對頁表等快慢表式結(jié)構(gòu)同理象对。
參考:
本文鏈接:淺談linux線程模型和線程切換
作者:猴子007
出處:https://monkeysayhi.github.io
本文基于 知識共享署名-相同方式共享 4.0 國際許可協(xié)議發(fā)布,歡迎轉(zhuǎn)載宴抚,演繹或用于商業(yè)目的勒魔,但是必須保留本文的署名及鏈接。