//從別處拷貝過來的,只作為自己查看方便,原作者不詳,請諒解。
一:關於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>
#include <string.h>
void *thr_fn1(void *arg)
{
printf(“thread 1 returning.\n”);
return((void *)1);
}
void *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.
thread 1 exit code 1.
thread 2 exiting.
thread 2 exit code 2.
范例2:
#include <stdio.h>
#include <pthread.h>
void thread1(char s[])
{
printf("This is a pthread1.\n");
printf("%s\n",s);
pthread_exit("Hello first!"); //結束線程,返回一個值。
}
void thread2(char s[])
{
printf("This is a pthread2.\n");
printf("%s\n",s);
pthread_exit("Hello second!");
}
int 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");
exit (1);
}
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.
This is first thread!
Hello first!
This is the main process.
This 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()),從而導致進程及其所有線程結束運行。