linux線程庫詳解,還附帶(dai)典(dian)型實例(li)哦
							時(shi)間:2018-07-18      來源:未知 
							在linux環境下的并(bing)發(fa)程(cheng)序(xu)設計有兩個選擇(ze),分別是多(duo)進(jin)程(cheng)并(bing)發(fa)與多(duo)線(xian)程(cheng)并(bing)發(fa)。
關于(yu)多進程(cheng)(cheng)與多線程(cheng)(cheng)編(bian)程(cheng)(cheng)之(zhi)前已經有很(hen)(hen)多博(bo)文介(jie)紹過(guo)了,但關于(yu)線程(cheng)(cheng)庫的(de)介(jie)紹卻很(hen)(hen)少。
在linux環境下當采用(yong)多線(xian)(xian)程(cheng)編(bian)程(cheng)時,需要在編(bian)譯的(de)時候加上-lpthread(或-pthread) 以顯示鏈(lian)接該庫(ku)(ku)(ku)。之所以這樣是因為(wei)pthread并非Linux系統的(de)默(mo)認庫(ku)(ku)(ku),而(er)是POSIX線(xian)(xian)程(cheng)庫(ku)(ku)(ku)。而(er)說(shuo)起(qi)線(xian)(xian)程(cheng)庫(ku)(ku)(ku)并不是一句話(hua)能(neng)夠說(shuo)得清(qing)楚,因為(wei)這涉及到了Linux內(nei)核(he)和線(xian)(xian)程(cheng)庫(ku)(ku)(ku)的(de)發展史。
起初(chu)在線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)概念(nian)(nian)出現(xian)(xian)(xian)之后,并(bing)沒(mei)(mei)有(you)(you)在類unix操(cao)作系統(tong)中(zhong)得到廣泛支(zhi)持。比(bi)如在linux2.4以(yi)及(ji)以(yi)前版(ban)本,因(yin)為(wei)還沒(mei)(mei)有(you)(you)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)的(de)(de)(de)(de)(de)(de)(de)(de)概念(nian)(nian),linux內(nei)核(he)不知道(dao)什么是(shi)(shi)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng),程(cheng)(cheng)(cheng)(cheng)序員也(ye)就(jiu)沒(mei)(mei)有(you)(you)辦法在操(cao)作系統(tong)上(shang)創建線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)。而(er)后來(lai)(lai)(lai)隨著技術發展,線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)帶來(lai)(lai)(lai)的(de)(de)(de)(de)(de)(de)(de)(de)好處被(bei)大家(jia)所認識,因(yin)為(wei)創建進程(cheng)(cheng)(cheng)(cheng)開銷的(de)(de)(de)(de)(de)(de)(de)(de)資源(yuan)更多,且進程(cheng)(cheng)(cheng)(cheng)間的(de)(de)(de)(de)(de)(de)(de)(de)切換相比(bi)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)更慢。于(yu)(yu)是(shi)(shi)我們(men)希望(wang)Linux能實現(xian)(xian)(xian)多線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)編程(cheng)(cheng)(cheng)(cheng),然(ran)而(er)要修改(gai)一個操(cao)作系統(tong)并(bing)不是(shi)(shi)件容(rong)易的(de)(de)(de)(de)(de)(de)(de)(de)事情,于(yu)(yu)是(shi)(shi)采用的(de)(de)(de)(de)(de)(de)(de)(de)辦法是(shi)(shi)寫函數(shu)(shu)來(lai)(lai)(lai)實現(xian)(xian)(xian),而(er)不是(shi)(shi)去修改(gai)操(cao)作系統(tong)的(de)(de)(de)(de)(de)(de)(de)(de)內(nei)核(he)。而(er)這(zhe)(zhe)些函數(shu)(shu)也(ye)就(jiu)是(shi)(shi)最初(chu)的(de)(de)(de)(de)(de)(de)(de)(de)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)庫,由于(yu)(yu)在linux內(nei)核(he)中(zhong)沒(mei)(mei)有(you)(you)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)的(de)(de)(de)(de)(de)(de)(de)(de)概念(nian)(nian),因(yin)此這(zhe)(zhe)種線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)是(shi)(shi)用進程(cheng)(cheng)(cheng)(cheng)來(lai)(lai)(lai)模(mo)擬(ni)的(de)(de)(de)(de)(de)(de)(de)(de),實際上(shang)在不同的(de)(de)(de)(de)(de)(de)(de)(de)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)內(nei)調用getpid()函數(shu)(shu),就(jiu)會發現(xian)(xian)(xian)得到的(de)(de)(de)(de)(de)(de)(de)(de)值不同,因(yin)為(wei)它們(men)在內(nei)核(he)的(de)(de)(de)(de)(de)(de)(de)(de)進程(cheng)(cheng)(cheng)(cheng)鏈表中(zhong)有(you)(you)不同的(de)(de)(de)(de)(de)(de)(de)(de)task_struct結構體來(lai)(lai)(lai)表示,有(you)(you)各自不同的(de)(de)(de)(de)(de)(de)(de)(de)進程(cheng)(cheng)(cheng)(cheng)標(biao)識符(fu)PID。因(yin)此這(zhe)(zhe)種線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)也(ye)被(bei)稱(cheng)為(wei)用戶級線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)。雖然(ran)當時的(de)(de)(de)(de)(de)(de)(de)(de)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)庫已經和POSIX的(de)(de)(de)(de)(de)(de)(de)(de)標(biao)準(zhun)非常接近了,但是(shi)(shi)在linux的(de)(de)(de)(de)(de)(de)(de)(de)線(xian)(xian)(xian)(xian)程(cheng)(cheng)(cheng)(cheng)實現(xian)(xian)(xian)版(ban)本和POSIX標(biao)準(zhun)之間還是(shi)(shi)存(cun)在著細(xi)微的(de)(de)(de)(de)(de)(de)(de)(de)差別,最明顯的(de)(de)(de)(de)(de)(de)(de)(de)是(shi)(shi)關于(yu)(yu)信號處理部分,這(zhe)(zhe)些差別中(zhong)的(de)(de)(de)(de)(de)(de)(de)(de)大部分都受底層linux內(nei)核(he)的(de)(de)(de)(de)(de)(de)(de)(de)限(xian)制,而(er)不是(shi)(shi)函數(shu)(shu)所能改(gai)變的(de)(de)(de)(de)(de)(de)(de)(de)。
許多項目都(dou)在研究(jiu)如何才(cai)能改(gai)善linux對線程的(de)支(zhi)持(chi),當然這種改(gai)善不(bu)僅僅是(shi)清除POSIX標準和linux具體(ti)實現之間的(de)細微差別,還要增強linux線程的(de)性能和刪除一些不(bu)需(xu)要的(de)限制,這其中大部分工作(zuo)集中在了如何將用戶(hu)級的(de)線程映射到內核級的(de)線程。
其中IBM公(gong)司(si)的(de)(de)(de)NGPT(Next Generation POSIX Threads),和Redhat公(gong)司(si)的(de)(de)(de)NPTL(Native POSIX Thread Library)通(tong)過(guo)(guo)修改(gai)linux內(nei)核(he)來支持新的(de)(de)(de)線(xian)(xian)程(cheng)(cheng)(cheng)庫,兩(liang)者都極大地提升了(le)性能。在2002年(nian),NGPT項目(mu)組(zu)宣(xuan)布,由(you)于不希望分(fen)化團隊,所(suo)以停止(zhi)為(wei)NGPT添(tian)新功能,而(er)只(zhi)是繼續進行(xing)linux上的(de)(de)(de)線(xian)(xian)程(cheng)(cheng)(cheng)支持工作(zuo),從而(er)有(you)效(xiao)地將(jiang)他們(men)的(de)(de)(de)重擔放到(dao)了(le)NPTL的(de)(de)(de)身上。也(ye)因此NPTL成為(wei)了(le)linux線(xian)(xian)程(cheng)(cheng)(cheng)的(de)(de)(de)新標(biao)準。NPTL有(you)了(le)很多優點:沒有(you)使(shi)用(yong)(yong)管理(li)(li)(li)線(xian)(xian)程(cheng)(cheng)(cheng)。因為(wei)管理(li)(li)(li)線(xian)(xian)程(cheng)(cheng)(cheng)的(de)(de)(de)一(yi)些(xie)需(xu)求,例如向作(zuo)為(wei)進程(cheng)(cheng)(cheng)一(yi)部分(fen)的(de)(de)(de)所(suo)有(you)線(xian)(xian)程(cheng)(cheng)(cheng)發送終(zhong)止(zhi)信號(hao),是并不需(xu)要(yao)的(de)(de)(de),因為(wei)內(nei)核(he)本身就(jiu)可以實(shi)現這些(xie)功能。內(nei)核(he)還(huan)會處理(li)(li)(li)每個線(xian)(xian)程(cheng)(cheng)(cheng)堆棧所(suo)使(shi)用(yong)(yong)的(de)(de)(de)內(nei)存的(de)(de)(de)回收工作(zuo)。它甚至還(huan)通(tong)過(guo)(guo)在清除父線(xian)(xian)程(cheng)(cheng)(cheng)之前(qian)進行(xing)等待,從而(er)實(shi)現對(dui)所(suo)有(you)線(xian)(xian)程(cheng)(cheng)(cheng)結束的(de)(de)(de)管理(li)(li)(li),這樣(yang)可以避免僵尸進程(cheng)(cheng)(cheng)的(de)(de)(de)問題。
最后(hou)關于編(bian)譯(yi)參數-lpthread與-pthread其實(shi)是有區別的。主(zhu)要在可移植性和安全性上(shang)。
在(zai)Linux中,pthread是作為(wei)一個(ge)(ge)單(dan)(dan)獨的(de)(de)(de)(de)庫存在(zai)的(de)(de)(de)(de)(libpthread.so),但是在(zai)其他(ta)Unix變種中卻不(bu)一定(ding)(ding),比(bi)(bi)如(ru)在(zai)FreeBSD中是沒(mei)有(you)單(dan)(dan)獨的(de)(de)(de)(de)pthread庫的(de)(de)(de)(de),因(yin)此在(zai)FreeBSD中不(bu)能(neng)(neng)使(shi)用(yong)(yong)-lpthread來鏈(lian)接(jie)pthread,而(er)使(shi)用(yong)(yong)-pthread則不(bu)會(hui)(hui)存在(zai)這(zhe)個(ge)(ge)問(wen)題(ti),因(yin)為(wei)FreeBSD的(de)(de)(de)(de)編(bian)譯器能(neng)(neng)正確(que)將-pthread展開為(wei)該系統(tong)下的(de)(de)(de)(de)依賴參數(shu)。同樣道理,其他(ta)不(bu)同的(de)(de)(de)(de)變種也會(hui)(hui)有(you)這(zhe)樣那樣的(de)(de)(de)(de)區別(bie),如(ru)果使(shi)用(yong)(yong)-lpthread,則可能(neng)(neng)在(zai)移(yi)植(zhi)到其他(ta)Unix變種中時會(hui)(hui)出現問(wen)題(ti),為(wei)了(le)保(bao)持(chi)較高的(de)(de)(de)(de)可移(yi)植(zhi)性(xing),我們最(zui)好還是使(shi)用(yong)(yong)-pthread。在(zai)多數(shu)系統(tong)中,-pthread會(hui)(hui)被展開為(wei)-D_REENTRANT -lpthread,即是除了(le)鏈(lian)接(jie)pthread庫外,還先定(ding)(ding)義(yi)了(le)宏_REENTRANT。定(ding)(ding)義(yi)這(zhe)個(ge)(ge)宏的(de)(de)(de)(de)目的(de)(de)(de)(de),是為(wei)了(le)打開系統(tong)頭文件(jian)中的(de)(de)(de)(de)各種多線(xian)程支持(chi)分支。比(bi)(bi)如(ru),我們常(chang)常(chang)使(shi)用(yong)(yong)的(de)(de)(de)(de)錯誤碼標志errno,如(ru)果沒(mei)有(you)定(ding)(ding)義(yi)_REENTRANT,則實現為(wei)一個(ge)(ge)全局變量;若是定(ding)(ding)義(yi)了(le)_REENTRANT,則會(hui)(hui)實現為(wei)每線(xian)程獨有(you),從(cong)而(er)避免(mian)線(xian)程競爭(zheng)錯誤。綜上所述(shu),在(zai)編(bian)譯和鏈(lian)接(jie)時都使(shi)用(yong)(yong)-pthread 選(xuan)項而(er)不(bu)是傳(chuan)統(tong)的(de)(de)(de)(de)-lpthread能(neng)(neng)夠保(bao)持(chi)向后兼容(rong)性(xing)和安全性(xing)。
Linux環境創建線程(cheng)的(de)實例。
  #include 
 #include 
 #include 
 #include 
 #include 
void *child_pthread(void *argc)
{
while(1)
{
printf("子線程(cheng)process pid:%d,thread's id=%u\n",getpid(),(unsigned int)pthread_self());
sleep(2);
}
}
int main(void)
{
int ret;
pthread_t pid;
ret = pthread_create(&pid,NULL,child_pthread,NULL);
if(ret){
perror("pthread_create");
exit(0);
}
while(1)
{
printf("主線程process pid:%d,thread's id:%u\n",getpid(),(unsigned int)pthread_self());
sleep(2);
}
return 0;
}
在linux環境下創建線程采用pthread_create()
頭文件
  #include
函數聲明
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
返回值
若成(cheng)功則返(fan)回(hui)0,否則返(fan)回(hui)出錯編(bian)號
編譯(yi)運(yun)行結果(guo)如下(xia)圖所(suo)示,其中編譯(yi)選項-pthread指定鏈(lian)接線(xian)程(cheng)庫(ku)。運(yun)行結果(guo)主線(xian)程(cheng)與子線(xian)程(cheng)的進程(cheng)id一致,線(xian)程(cheng)id則不同。
  

