Linux線程 之 線程 線程組 進(jìn)程 輕量級(jí)進(jìn)程(LWP)_第1頁(yè)
Linux線程 之 線程 線程組 進(jìn)程 輕量級(jí)進(jìn)程(LWP)_第2頁(yè)
Linux線程 之 線程 線程組 進(jìn)程 輕量級(jí)進(jìn)程(LWP)_第3頁(yè)
Linux線程 之 線程 線程組 進(jìn)程 輕量級(jí)進(jìn)程(LWP)_第4頁(yè)
Linux線程 之 線程 線程組 進(jìn)程 輕量級(jí)進(jìn)程(LWP)_第5頁(yè)
已閱讀5頁(yè),還剩4頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Linux線程之線程線程組進(jìn)程輕量級(jí)進(jìn)程(LWP)ThreadLocalStorage,線程本地存儲(chǔ),大神UlrichDrepper有篇PDF文檔是講TLS的,我曾經(jīng)努力過三次嘗試搞清楚TLS的原理,均沒有徹底搞清楚。這一次是第三次,我沉浸glibc的源碼和kernel的源碼中,做了一些實(shí)驗(yàn),也有所得。對(duì)Linux的線程有了進(jìn)一步的理解。線程是有棧的,我們知道,普通的一個(gè)進(jìn)程,它的棧空間是8M我們可以通過ulmit-a查看:stacksize(kbytes,-s)8192線程也不例外,線程也是需要??臻g的這句話是廢話,呵呵。對(duì)于屬于同一個(gè)進(jìn)程(或者說是線程組)的多個(gè)線程他們是共享一份虛擬內(nèi)存地址的,如下圖所示。這也就決定了,你不能無(wú)限制創(chuàng)建線,因?yàn)榭v然你什么都不做,每個(gè)線程默認(rèn)耗費(fèi)8M的空間(事實(shí)上還不止,還有管理結(jié)構(gòu),后面陳述)UlrichDrepper大神有篇文章(Threadnumbersandstacks》,分析了線程??臻g方面的計(jì)算。如果我們真的需要很多個(gè)線程的話,幸好我們還是可以做一些事情。我們可以通過pthread_attr_setstacksize,設(shè)定好stacksize屬性然后在pthread_pthread_attr_setstacksize(pthread_attr_t*attr,size_tstacksize);intpthread_create(pthread_t*thread,constvoidpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);線程棧如上圖所示,共享進(jìn)程(或者稱之為線程組)的虛擬地址空間。既然多個(gè)線程聚集在一起,我怎么知道我要操作的那個(gè)線程棧的地址呢。要解決這個(gè)問題,必須要領(lǐng)會(huì)線程和進(jìn)程以及線程組的概念。我不想寫一堆片湯話,下面我運(yùn)行我的測(cè)試程序,然后結(jié)合現(xiàn)象分析原因:#include<stdio.h>#include<pthread.h>#include<sys/syscall.h>#include<assert.h>#definegettid()syscall(__NR_gettid)pthread_key_tkey;__threadintcount=2222;__threadunsignedlonglongcount2;static__threadintcount3;voidechomsg(intt){printf("destructorexcutedinthread%x,param=%x\n",pthread_self(),t);}void*child1(void*arg){intb;inttid=pthread_self();printf("Iamthechild1pthread_selfreturn%pgettidreturn%d\n",tid,gettid());char*key_content=malloc(8);if(key_content!=NULL){strcpy(key_content,"ACACACA");}pthread_setspecific(key,(void*)key_content);count=666666;count2=1023;count3=2048;

printf("Iamchild1,tid=%x,count(%p)=%10d,count2(%p)=%10llu,count3(%p)=%6d\n",tid,&count,count,&count2,count2,&count3,count3);asmvolatile("movl%%gs:0,%0;":"=r"(b)/*output*/);printf("Iamchild1,GSaddress%x\n",b);sleep(2);printf("thread%xreturns%x\n",tid,pthread_getspecific(key));sleep(50);}void*child2(void*arg){intb;inttid=pthread_self();printf("Iamthechild2pthread_selfreturn%pgettidreturn%d\n",tid,gettid());char*key_content=malloc(8);if(key_content!=NULL){strcpy(key_content,"ABCDEFG");}pthread_setspecific(key,(void*)key_content);count=88888888;count2=1024;count3=2047;printf("Iamchild2,tid=%x,count(%p)=%10d,count2(%p)=%10llu,count3(%p)=%6d\n",tid,&count,count,&count2,count2,&count3,count3);asmaddress%x\n",b);volatile("movl%%gs:0,%0;":"=r"(b)/*output*/);printf("Iamchild2,GSaddress%x\n",b);sleep(1);printf("thread%xreturns%x\n",tid,pthread_getspecific(key));sleep(50);}intmain(void){intb;pthread_ttid1,tid2;printf("hello\n");pthread_key_create(&key,echomsg);asmvolatile("movl%%gs:0,%0;":"=r"(b)/*output*/);printf("Iamthemain,GSaddress%x\n",b);pthread_create(&tid1,NULL,child1,NULL);pthread_create(&tid2,NULL,child2,NULL);printf("pthread_createtid1=%p\n",tid1);printf("pthread_createtid2=%p\n",tid2);sleep(60);pthread_key_delete(key);printf("mainthreadexit\n");return0;}這是一個(gè)比較綜合的程序,因?yàn)槲蚁旅嬉啻螐牟煌膫?cè)面分析。對(duì)于現(xiàn)在,我們要展示的是進(jìn)程線程線程組的關(guān)系。在一個(gè)終端運(yùn)行編譯岀來(lái)的test2程序,顯示的信息如下:另一個(gè)終端看ps信息,ps顯示的信息如下:直接ps,是看不到我們創(chuàng)建的線程的。只有3658一個(gè)進(jìn)程。當(dāng)我們采用ps-eLf的時(shí)候,我們看到了三個(gè)線程3658/3659/3660,或者稱之為輕量級(jí)進(jìn)程(LWP)Linux到底是怎么看待這三者的關(guān)系的呢:Linux下多線程程序,一般都是有一個(gè)主進(jìn)程通過調(diào)用pthread_create創(chuàng)建了一個(gè)或者多個(gè)子線程,如同我們的程序,主進(jìn)程在main中創(chuàng)建了兩個(gè)子進(jìn)程。那么Linux到底是怎么看待這些事情的呢?pid_tpid;pid_ttgid;...structtask_struct*group_leader;/*threadgroupleader*/上面三個(gè)變量是進(jìn)程描述符的三個(gè)成員變量。pid字面意思是processid,其實(shí)叫threadid會(huì)更合適。tgid字面含義是threadgroupID。對(duì)于存在多個(gè)線程的程序而言,每個(gè)線程都有自己的pid,沒錯(cuò)pid,如同我們例子中的3658/3659/3660,但是都有個(gè)共同的線程組ID(TGID):3658。好吧,我們?cè)僦匦抡f一遍,對(duì)于普通進(jìn)程而言,我們可以稱之為只有一個(gè)LWP的線程組,pid是它自己的pid,tgid還是它自己,線程組里面只有他自己一個(gè)光桿司令,自然group_leader也是它自己。但是多線程的進(jìn)程(線程組更恰當(dāng))則不然。開天辟地的main函數(shù)所在的進(jìn)程會(huì)有自己的PID,也會(huì)有也TGID,group_leader,都是他自己。注意,它自己也是LWP。后面他使用ptherad_create創(chuàng)建了2個(gè)線程,或者LWP,這兩個(gè)新創(chuàng)建的線程會(huì)有自己的PID,但是TGID會(huì)沿用創(chuàng)建自己的那個(gè)進(jìn)程的TGID,group_leader也會(huì)尊創(chuàng)建自己的進(jìn)程的進(jìn)程描述符(task_struct)為自己的group_leader。copy_process函數(shù)中有如下代碼:p->pid=pid_nr(pid);p->tgid=p->pid;〃普通進(jìn)程if(clone_flags&CLONE_THREAD)p->tgid=current->tgid;〃線程選擇叫起它的進(jìn)程的tgid作為自己的tgidp->group_leader=p;//普通進(jìn)程INIT_LIST_HEAD(&p->thread_group);if(clone_flags&CLONE_THREAD){current->signal->nr_threads++;atomic_inc(&current->signal->live);atomic_inc(&current->signal->sigcnt);p->group_leader=current->group_leader;//線程選擇叫起它的進(jìn)程作為它的group_leaderlist_add_tail_rcu(&p->thread_group,&p->group_leader->thread_group);}OK,ps-eLf中有個(gè)字段叫NLWP,就是線程組中LWP的個(gè)數(shù),對(duì)于我們的例子main函數(shù)所在LWP+兩個(gè)線程二3.我們傳說的getpid函數(shù),本質(zhì)取得是進(jìn)程描述符的TGID,而gettid系統(tǒng)調(diào)用,取得才是每個(gè)LWP各自的PID。請(qǐng)看上面的圖片輸出,上面連個(gè)線程gettid返回的是3873和3874,是自己的PID。稍微有點(diǎn)毀三觀除此外,需要指出的是用戶態(tài)pthread_create出來(lái)的線程,在內(nèi)核態(tài),也擁有自己的進(jìn)程描述符task_struct(copy_process里面調(diào)用dup_task_struct創(chuàng)建)。這是什么意思呢。意思是我們用戶態(tài)所說的線程,一樣是內(nèi)核進(jìn)程調(diào)度的實(shí)體。進(jìn)程調(diào)度,嚴(yán)格意義上說應(yīng)該叫LWP調(diào)度,進(jìn)程調(diào)度,不是以前面提到的線程組為單位調(diào)度的,本質(zhì)是以LWP為單位調(diào)度的。這個(gè)結(jié)論乍一看驚世駭俗,細(xì)細(xì)一想,其是很合理。我們?yōu)槭裁炊嗑€程?因?yàn)槎郈PU,多核,我們要充分利用多核,同一個(gè)線程組的不同LWP是可以同時(shí)跑在不同的CPU之上的,因?yàn)檫@個(gè)并發(fā),所以我們有線程鎖的設(shè)計(jì),這從側(cè)面證明了,LWP是調(diào)度的實(shí)體。我們用systemtap去觀察下test2程序相關(guān)的調(diào)度:systemtap腳本如下:#!/usr/bin/envstap##globaltime_offsetprobebegin{time_offset=gettimeofday_us()printf("monitorbegin==========\n")}probescheduler.cpu_off{if(task_execname(task_next)=="test2"){t=gettimeofday_us();printf("%9d:%20s(%6d)->%10s(%6d:%6d)\n",t-time_offset,task_execname(task_prev),task_pid(task_prev),task_execname(task_next),task_pid(task_next),#返回的是內(nèi)核中的TGIDtask_tid(

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論