pthread_join和pthread_detach的用法

轉自: https://www.cnblogs.com/sanchrist/p/3566313.html

一:關於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()),從而導致進程及其所有線程結束運行。

穩定、高效、健壯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章