linux 线程_浅谈Linux线程模型
Thread Basic
基礎(chǔ)概念
線程是操作系統(tǒng)能夠調(diào)度和執(zhí)行的基本單位,在Linux中也被稱之為輕量級進程。從定義中可以看出,線程它是操作系統(tǒng)的概念,在不同的操作系統(tǒng)中的實現(xiàn)是不同的,不過今天分享的豬腳是Linux Thread。
對于Linux操作系統(tǒng)而言,它對Thread的實現(xiàn)方式比較特殊。在Linux內(nèi)核中,其實是沒有線程的概念的,它把所有的線程當做標準的進程來實現(xiàn),也就是說Linux內(nèi)核,并沒有為線程提供任何特殊的調(diào)度語義,也沒有為線程實現(xiàn)特定的數(shù)據(jù)結(jié)構(gòu)。取而代之的是,線程只是一個與其他進程共享某些資源的進程。每一個線程擁有一個唯一的task_struct結(jié)構(gòu),Linux內(nèi)核它僅僅把線程當做一個正常的進程,或者說是輕量級進程,LWP(Lightweight processes)。
對于其他的操作系統(tǒng)而言,比如windows,線程相對于進程,只是一個提供了更加輕量、快速執(zhí)行單元的抽象概念。對于Linux而言,線程只是進程間共享資源的一種方式,非常輕量。舉個簡單例子,假設(shè)有一個進程包含了N個線程。對于那些顯示支持線程的操作系統(tǒng)而言,應(yīng)該是存在一個進程描述符,依次輪流指向N個線程。這個進程描述符指明共享資源,包括內(nèi)存空間和打開的文件,然后線程描述它們自己獨享的資源。相反的是在Linux中,只有N個進程,因此有N個task_struct數(shù)據(jù)結(jié)構(gòu),只是這些數(shù)據(jù)結(jié)構(gòu)的某些資源項是共享的。
這里再總結(jié)一下,Linux線程是進程資源共享的一種方式,而其他操作系統(tǒng),線程則是一種實現(xiàn)輕量、快速執(zhí)行單元的抽象概念或者實體。這里再深入的理解一下,Linux中的線程和進程的區(qū)別。這也是諸多面試題中,最常見的一個。
資源共享
Linux線程與進程的區(qū)別,主要體現(xiàn)在資源共享、調(diào)度、性能幾個方面,首先看一下資源共享方面。上面也提到,線程其實是共享了某一個進程的資源,這些資源包括:
- 內(nèi)存地址空間
- 進程基礎(chǔ)信息
- 大部分數(shù)據(jù)
- 打開的文件
- 信號處理
- 當前工作目錄
- 用戶和用戶組屬性
- 等等
哪些是線程獨自擁有的呢?
- 線程ID
- 一系列的寄存器
- 棧的局部變量和返回地址
- 錯誤碼 errno
- 信號掩碼
- 優(yōu)先級
- 等等
這里說一個黑科技,線程擁有獨立的調(diào)用棧,除了棧之外共享了其他所有的段segment。但是由于線程間共享了內(nèi)存,也就是說一個線程,理論上是可以訪問到其他線程的調(diào)用棧的,可以用一個指針變量,去訪問其他線程的局部棧幀,以訪問其他線程的局部變量。
調(diào)度
說到調(diào)度,就得提到進程的上下文切換。上下文切換也被稱作為進程調(diào)度或者任務(wù)切換,簡單的來說是把CPU從一個進程或者線程切換到另一個執(zhí)行。概括的來說,線程的上下文切換,要比進程更加快速,因為本質(zhì)上,線程很多資源都是共享進程的,所以切換時,需要保存和切換的項是很少的。
線程上線文切換時,虛擬地址空間是不變的,但是進程上下文切換時,是需要重新映射虛擬地址空間。進程切換上下文時,進出OS內(nèi)核&寄存器切換,是最大的時間支出。更模糊的代價是上下文切換時,會干擾處理器的緩存機制。當上下文切換時,處理器需要重新cache一些內(nèi)存。
這里更大的一個區(qū)別時,當更改虛擬地址空間時,CPU 的 TLB 等也會被刷新,導(dǎo)致接下來的內(nèi)存訪問更加耗時,所以相對線程切換來說,進程的切換耗時更大。
性能
從性能方面,來查看一下線程與進程的對比。由于線程更加輕量,導(dǎo)致線程的創(chuàng)建速度、切換速度都要高于進程。這里就有一個疑問了,從上面提到的各個方面來看,好像線程都要優(yōu)于進程,那么有沒有啥缺點呢?
線程缺點
線程同樣也有缺點,最大的缺點是線程的不安全性,缺乏保護機制。就是上面提到的黑科技,因為線程間共享數(shù)據(jù),一個線程可以重寫另外一個線程的堆棧,導(dǎo)致出現(xiàn)一些異常的情況。除此之外,線程還有以下缺點:
- 共享屬性:全局變量是在所有線程間共享的,訪問時是需要同步加鎖。
- 很多庫函數(shù)是線程非安全的,多線程編程時,需要注意這一點。
- 線程的健壯性不強,如果一個線程crash了,那么整個應(yīng)用程序就跪了。
應(yīng)用場景
上面提到了線程與進程的對比,也提到了線程的優(yōu)點和缺點,那么什么情況下適合用線程呢?簡單的來說,計算密集型的任務(wù),適合于多線程來處理。因為計算密集型任務(wù),需要耗費很多CPU,上下文的切換是非常頻繁的,而線程切換速度是高于進程的,所以使用線程是更加適合的。在實際的編程過程中,根據(jù)業(yè)務(wù)的場景,再結(jié)合進程和線程的優(yōu)缺點對比,來決定適合的編程模型。
線程創(chuàng)建
那么Linux中線程是如何創(chuàng)建出來的呢?上面也提到,在Linux中線程是一種資源共享的方式,可以在創(chuàng)建進程的時候,指定某些資源是從其他進程共享的,從而在概念上創(chuàng)建了一個線程。在Linux中,可以通過clone系統(tǒng)調(diào)用來創(chuàng)建一個進程,它的函數(shù)簽名如下:
#include <sched.h> int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);我們在使用clone創(chuàng)建進程的過程中,可以指明相應(yīng)的參數(shù),來決定共享某些資源,比如:
clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);這個clone系統(tǒng)調(diào)用的行為類似于fork,不過新創(chuàng)建出來的進程,它的內(nèi)存地址、文件系統(tǒng)資源、打開的文件描述符和信號處理器,都是共享父進程的。換句話說,這個新創(chuàng)建出來的進程,也被叫做Linux Thread。從這個例子中,也可以看出Linux中,線程其實是進程實現(xiàn)資源共享的一種方式。
內(nèi)核線程
在Linux中,還存在一個Kernel Thread的概念,也就是內(nèi)核線程。內(nèi)核創(chuàng)建一些內(nèi)核線程來執(zhí)行一些后臺任務(wù)。相對于普通的進程,內(nèi)核線程完整的存在于內(nèi)核空間,是沒有自己的地址空間的,也就是mm指針為空,它的操作僅存在于內(nèi)核態(tài),并且也不會上下文切換到用戶態(tài)。不過內(nèi)核線程和普通進程類似的是,是可調(diào)度和可搶占的。
同步
由于線程間共享了很多資源,所以在多線程的編程環(huán)境下,為了保障結(jié)果的準確性和一致性,需要對共享資源的訪問進行同步。常見的同步方式,也就是加鎖,以保障操作共享資源時,不會出錯。在Linux中,鎖的種類大致有四種:
- 互斥鎖
- 讀寫鎖
- 條件變量
- 自旋鎖
- 內(nèi)存屏障
有興趣的同學(xué),看看看下這篇文章:http://blog.lecury.cn/2016/02/21/%E5%90%8C%E6%AD%A5%E4%BA%92%E6%96%A5(%E9%94%81).html ??偨Y(jié)來說,鎖的代價是高昂的,所以在設(shè)計高并發(fā)、高吞吐的程序時,盡量避免鎖的使用,或者減少鎖的區(qū)間。
常見的多線程編程模式
下面談一下實際工作中,要如何合理的線程呢?這里我簡單的提出三種常見的線程模型。
- leader-follow 模型(主從)
- 線程與連接對應(yīng),并發(fā)度等于線程數(shù)。
- 所有線程經(jīng)歷accept->close整個過程。
- 適用于連接數(shù)少、處理時間長、CPU密集型服務(wù)。
- producer-consumer模型(生產(chǎn)者消費者)
- 主線程用于accept請求,并將fd放置在消費隊列pendingpool中。
- pendingpool進行連接的維護工作。
- 多個worker競爭pendingpool的連接。
- 適用于連接數(shù)多、處理速度快的業(yè)務(wù)。
- 高并發(fā)索引模型
- 無鎖設(shè)計
- 將請求或者事務(wù)映射到具體線程處理
踩過的坑和小技巧
- 同步
- 過載保護
- 公平調(diào)度
- 析構(gòu)出core
更加詳細的內(nèi)容,請參考知乎Live:
如何理解和應(yīng)用Linux線程模型??www.zhihu.com感興趣的同學(xué),可以加QQ群: 853832829 一起學(xué)習(xí)~
總結(jié)
以上是生活随笔為你收集整理的linux 线程_浅谈Linux线程模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: scheduledexecutorser
- 下一篇: 电脑音响怎么插_厦门汽车音响改装丰田RA