天天看點

pthread_join和pthread_detach的用法

//從别處拷貝過來的,隻作為自己檢視友善,原作者不詳,請諒解。 

一:關于join 

join 

join是三種同步線程的方式之一。另外兩種分别是互斥鎖(mutex)和條件變量(condition

variable)。 

調用pthread_join()将阻塞自己,一直到要等待加入的線程運作結束。 

可以用pthread_join()擷取線程的傳回值。 

一個線程對應一個pthread_join()調用,對同一個線程進行多次pthread_join()調用是邏輯錯誤。 

join

or detach 

線程分兩種:一種可以join,另一種不可以。該屬性在建立線程的時候指定。 

joinable線程可在建立後,用pthread_detach()顯式地分離。但分離後不可以再合并。該操作不可逆。 

為了確定移植性,在建立線程時,最好顯式指定其join或detach屬性。似乎不是所有POSIX實作都是用joinable作預設。 

二:

pthread_detach 

建立一個線程預設的狀态是joinable,

如果一個線程結束運作但沒有被join,則它的狀态類似于程序中的Zombie

Process,即還有一部分資源沒有被回收(退出狀态碼),是以建立線程者應該調用pthread_join來等待線程運作結束,并可得到線程的退出代碼,回收其資源(類似于wait,waitpid) 

但是調用pthread_join(pthread_id)後,如果該線程沒有運作結束,調用者會被阻塞,在有些情況下我們并不希望如此,比如在Web伺服器中當主線程為每個新來的連結建立一個子線程進行處理的時候,主線程并不希望因為調用pthread_join而阻塞(因為還要繼續處理之後到來的連結),這時可以在子線程中加入代碼 

pthread_detach(pthread_self()) 

或者父線程調用 

pthread_detach(thread_id)(非阻塞,可立即傳回) 

這将該子線程的狀态設定為detached,則該線程運作結束後會自動釋放所有資源。 

三:pthread_join 

調用pthread_join的線程會阻塞,直到指定的線程傳回,調用了pthread_exit,或者被取消。 

如果線程簡單的傳回,那麼rval_ptr被設定成線程的傳回值,參見範例1;如果調用了pthread_exit,則可将一個無類型指針傳回,在pthread_join中對其進行通路,參見範例2;如果線程被取消,rval_ptr被設定成PTHREAD_CANCELED。 

如果我們不關心線程的傳回值,那麼我們可以把rval_ptr設定為NULL。 

範例1: 

#include

<pthread.h> 

<string.h> 

void

*thr_fn1(void *arg) 

printf(“thread 1 returning.\n”); 

return((void *)1); 

*thr_fn2(void *arg) 

printf(“thread 2 exiting.\n”); 

return((void *)2); 

int

main() 

pthread_t tid1,tid2; 

void *tret; 

pthread_create(&tid1,NULL,thr_fn1,NULL); 

pthread_create(&tid2,NULL,thr_fn2,NULL); 

pthread_join(tid1,&tret); 

printf(“thread 1 exit code %d\n”,(int)tret); 

pthread_join(tid2,&tret); 

printf(“thread 2 exit code %d\n”,(int)tret); 

exit(0); 

運作結果: 

thread

1 returning. 

1 exit code 1. 

2 exiting. 

2 exit code 2. 

範例2: 

<stdio.h> 

thread1(char s[]) 

printf("This is a pthread1.\n"); 

printf("%s\n",s); 

pthread_exit("Hello first!");  //結束線程,傳回一個值。 

thread2(char s[]) 

printf("This is a pthread2.\n"); 

pthread_exit("Hello second!"); 

main(void) 

pthread_t id1,id2; 

void *a1,*a2; 

int i,ret1,ret2; 

char s1[]="This is first thread!"; 

char s2[]="This is second thread!"; 

ret1=pthread_create(&id1,NULL,(void *) thread1,s1); 

ret2=pthread_create(&id2,NULL,(void *) thread2,s2); 

if(ret1!=0){ 

printf ("Create pthread1 error!\n"); 

exit (1); 

pthread_join(id1,&a1); 

printf("%s\n",(char*)a1); 

if(ret2!=0){ 

printf ("Create pthread2 error!\n"); 

printf("This is the  main process.\n"); 

pthread_join(id2,&a2); 

printf("%s\n",(char*)a2); 

return (0); 

[****@XD****

c]$ ./example 

This

is a pthread1. 

is first thread! 

Hello

first! 

is the main process. 

is a pthread2. 

<參考資料語> 

一般情況下,程序中各個線程的運作都是互相獨立的,線程的終止并不會通知,也不會影響其他線程,終止的線程所占用的資源也并不會随着線程的終止而得到釋

放。正如程序之間可以用wait()系統調用來同步終止并釋放資源一樣,線程之間也有類似機制,那就是pthread_join()函數 

pthread_join()的調用者将挂起并等待th線程終止,retval是pthread_exit()調用者線程(線程ID為th)的傳回值,如

果thread_return不為NULL,則*thread_return=retval。需要注意的是一個線程僅允許唯一的一個線程使用

pthread_join()等待它的終止,并且被等待的線程應該處于可join狀态,即非DETACHED狀态 

如果程序中的某個線程執行了pthread_detach(th),則th線程将處于DETACHED狀态,這使得th線程在結束運作時自行釋放所占用的

記憶體資源,同時也無法由pthread_join()同步,pthread_detach()執行之後,對th請求pthread_join()将傳回錯誤 

一個可join的線程所占用的記憶體僅當有線程對其執行了pthread_join()後才會釋放,是以為了避免記憶體洩漏,所有線程的終止,要麼已設為DETACHED,要麼就需要使用pthread_join()來回收 

3)

主線程用pthread_exit還是return 

用pthread_exit隻會使主線程自身退出,産生的子線程繼續執行;用return則所有線程退出。 

綜合以上要想讓子線程總能完整執行(不會中途退出),一種方法是在主線程中調用pthread_join對其等待,即pthread_create/pthread_join/pthread_exit或return;一種方法是在主線程退出時使用pthread_exit,這樣子線程能繼續執行,即pthread_create/pthread_detach/pthread_exit;還有一種是pthread_create/pthread_detach/return,這時就要保證主線程不能退出,至少是子線程完成前不能退出。現在的項目中用的就是第三種方法,主線程是一個死循環,子線程有的是死循環有的不是。 

理論上說,pthread_exit()和線程宿體函數退出的功能是相同的,函數結束時會在内部自動調用pthread_exit()來清理線程相關的資源。但實際上二者由于編譯器的處理有很大的不同。 

在程序主函數(main())中調用pthread_exit(),隻會使主函數所在的線程(可以說是程序的主線程)退出;而如果是return,編譯器将使其調用程序退出的代碼(如_exit()),進而導緻程序及其所有線程結束運作。