前言
我們編寫的絕大多數(shù)程序都需要涉及到多線程的并發(fā)編程,一般情況下都是采用glibc提供的線程庫進(jìn)行開發(fā)。
這里從線程庫的實(shí)現(xiàn)上來考慮對(duì)于并發(fā)情況下的編程模式。
從線程說起
線程是什么?
我們的多數(shù)程序都是運(yùn)行在多線程模式下,通過同時(shí)并發(fā)處理多個(gè)任務(wù)來處理不同的請(qǐng)求。線程的特點(diǎn)是共享地址空間,從而高效的共享數(shù)據(jù)。與進(jìn)程相比最大特點(diǎn)在于對(duì)于共享空間的簡單處理,雖然進(jìn)程間的數(shù)據(jù)共享采用mmap方式也很方便,但是畢竟涉及到共享內(nèi)存的使用,需要有一定的注意,和使用要求?!《嗑€程的概念引入,可以使得我們?cè)谝粋€(gè)進(jìn)程中可以同時(shí)處理多個(gè)業(yè)務(wù)邏輯,而不受影響(共享數(shù)據(jù)有同步原語支持)。在多核環(huán)境下也可以有效的利用多CPU的優(yōu)勢。
本質(zhì)上來說, 線程在實(shí)現(xiàn)上采用clone的調(diào)用方式利用在堆空間上分配的內(nèi)存作為,每個(gè)線程的??臻g(我們的環(huán)境中是10M或者8M,采用ulimt -s 可以看到)都是獨(dú)立,包含了當(dāng)前CPU的信息。目前常用的是2.6內(nèi)核(部分32位機(jī)器運(yùn)行在2.4內(nèi)核下),2.4內(nèi)核中是采用進(jìn)程來模擬線程,用ps命令可以看到有許多個(gè)進(jìn)程,在ps命令看來,線程基本上是等同于進(jìn)程。2.6內(nèi)核中一個(gè)多線程的進(jìn)程,只會(huì)顯示一個(gè)進(jìn)程,但用gdb 或者 pstack 查看程序依然可以看到
pthread_t 的意義, pthread_create創(chuàng)建線程的時(shí)候我們會(huì)拿到一個(gè)pthread_t 的返回值,在ullog中拿他做為線程號(hào)的標(biāo)記,這個(gè)值本質(zhì)上是維護(hù)線程數(shù)據(jù)的指針地址。 在ullog中采用這個(gè)作為線程的標(biāo)記其實(shí)是存在問題的,假設(shè)這樣的情況: 一個(gè)現(xiàn)程在啟動(dòng)后運(yùn)行一段時(shí)間才退出,而后再啟動(dòng),這個(gè)時(shí)候這個(gè)線程的數(shù)據(jù)依然會(huì)被復(fù)用,這個(gè)時(shí)候就出現(xiàn)了前后這兩個(gè)在我們概念中是不一樣的兩個(gè)線程被認(rèn)為是線程號(hào)相同的情況. 雖然我們?cè)诰€程啟動(dòng)和結(jié)束的時(shí)候都會(huì)有標(biāo)記特殊的日志
我們的glibc pthread的實(shí)現(xiàn)中,默認(rèn)棧空間是10M(一些機(jī)器上是8M),這些可以在線程啟動(dòng)的時(shí)候進(jìn)行修改。??臻g本質(zhì)上也是通過mmap的方式從堆上分配出來提供給沒個(gè)線程獨(dú)立使用。在具體的實(shí)現(xiàn)上,棧與棧之間一般都會(huì)存在一部分空間是不可寫同時(shí)也不可讀的,這也是為什么我們一旦棧溢出就很容易出core的原因。 ??臻g的大小可以在線程啟動(dòng)的時(shí)候修改或者通過ulimit方式進(jìn)行強(qiáng)制的改變。
注:如果不考慮進(jìn)程的可寫數(shù)據(jù)(只讀都是一樣)的共享,多進(jìn)程方式對(duì)比多線程其實(shí)優(yōu)勢更大,而且還有良好的安全性。
線程調(diào)度
在線程庫中對(duì)于線程的分配一般是受到內(nèi)存大小的控制, 而CPU的數(shù)量往往不多, 這里CPU在運(yùn)行的時(shí)候就涉及到,如何去運(yùn)作這些線程。每個(gè)線程只有獲得CPU的使用權(quán)才能執(zhí)行指令.所謂的多線程的并發(fā)運(yùn)行,從 宏觀上看.其實(shí)就是各個(gè)線程輪流或者CPU的使用權(quán),分別執(zhí)行各自的任務(wù).在可運(yùn)行池中,會(huì)有多個(gè)處于就緒狀態(tài)的線程在等待CPU。
在我們使用的線程庫中,調(diào)度往往需要考慮下面的方式
時(shí)間片,每個(gè)線程CPU運(yùn)行一段時(shí)間后,主動(dòng)讓出CPU
阻塞或休眠, 比如sleep, 等待鎖,系統(tǒng)調(diào)用等操作本身會(huì)讓CPU出現(xiàn)一定程度上的上下文切換
線程結(jié)束
主動(dòng)放棄CPU, 在我們的環(huán)境中是sched_yield, 可以主動(dòng)讓出CPU。
在我們現(xiàn)在64位機(jī)器上使用的都是基于nptl線程庫,相比32位中2.4內(nèi)核下的linuxthread本身有很的大的提高?;镜那袚Q上相差了近1倍。
雖然操作系統(tǒng)中已經(jīng)考慮了不少調(diào)度的問題,但是這些是實(shí)際中的表現(xiàn)往往不盡人意
時(shí)間片不可控,一些CPU消耗性程序其實(shí)可以多運(yùn)行一部分時(shí)間
上下文切換有一定的內(nèi)核態(tài)用戶態(tài)的切換。
大量的鎖應(yīng)用, 對(duì)性能會(huì)帶來一定的影響
當(dāng)存在大量長時(shí)間堵塞的時(shí)候, 需要大量的線程支持, 會(huì)對(duì)系統(tǒng)產(chǎn)生負(fù)面影響
這樣的基礎(chǔ)上,我們考慮采用一些其他方式來解決這些問題, 比如異步編程。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)
點(diǎn)擊舉報(bào)。