pthread_create線程終止問題


一直以為,程序創建線程,線程運行結束會自動清空資源 
最近在一個項目中用到了線程,除去業務邏輯,我把他簡化出來是下面這樣

//pthread.c 錯誤demo示例
#include <stdio.h>
#include <pthread.h>
static int testcount = 0;
static void *test_thread_handler()
{
    testcount++;
    printf("%d\n",testcount);
    return 0;
}

int main( int argc, char *argv[] )
{
    int ret = 0;
    pthread_t test_tid;
    while(1)
    {
        usleep(10000);
        ret = pthread_create(&test_tid, NULL, test_thread_handler,NULL);
        if(ret != 0)
        {
            printf("Create handler error :%d!\t testcount:%d\n", ret, testcount);
            return -1;
        }
    }
    return 0;
}

備注:pthread庫不是Linux系統默認的庫,連接時需要使用靜態庫libpthread.a,所以在線程函數在編譯時,需要連接庫函數

gcc pthread.c -o pthread -lpthread 
運行結果如下 


不同的機器上最終計數不同,但是結果應該是一樣的。 
pthread_create()返回11的錯誤碼表示Resource temporarily unavailable 
資源暫時不可用,按理說線程return 0后資源應該自動釋放,同時我使用free查看發現內存也是足夠的。

經過多方面查找資料,得知linux線程執行和windows不同,pthread有兩種狀態joinable狀態和unjoinable狀態,默認的狀態是joinable。

如果線程是joinable狀態,當線程函數自己返回退出時或pthread_exit時都不會釋放線程所占用堆棧和線程描述符(總計8K多),它的狀態類似於進程中的Zombie Process(僵屍進程)。只有當調用了pthread_join之后這些資源才會被釋放。

若是unjoinable狀態的線程,這些資源在線程函數退出時或pthread_exit時自動會被釋放。

但是調用pthread_join(pthread_id)后,如果該線程沒有運行結束,調用者會被阻塞,如果不需要阻塞的情況下,這時可以在子線程中加入代碼 
pthread_detach(pthread_self()) 
或者父線程調用 
pthread_detach(test_tid)(非阻塞,可立即返回) 
這將該子線程的狀態設置為detached,則該線程運行結束后會自動釋放所有資源。

最終程序如下:

//pthread.c 修復錯誤demo后示例
#include <stdio.h>
#include <pthread.h>

static int testcount = 0;

static void *test_thread_handler()
{
    pthread_detach(pthread_self());

    testcount++;
    printf("%d\n",testcount);

    pthread_exit(0);
    return 0;
}

int main( int argc, char *argv[] )
{
    pthread_t test_tid;
    int ret = 0;

    while(1)
    {
        usleep(10000);
        ret = pthread_create(&test_tid, NULL, test_thread_handler,NULL);
        if(ret != 0)
        {
            printf("Create handler error :%d!\t testcount:%d\n", ret, testcount);
            return -1;
        }
    }
    return 0;
}

 

不想在每個子線程里面pthread_detatch(pthread_self());而是希望在創建子線程的時候就指定好unjoinable屬性:

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

 

在任何一個時間點上,線程是可結合的(joinable),或者是分離的(detached)。一個可結合的線程能夠被其他線程收回其資源和殺死;在被其他線程回收之前,它的存儲器資源(如棧)是不釋放的。相反,一個分離的線程是不能被其他線程回收或殺死的,它的存儲器資源在它終止時由系統自動釋放。

        線程的分離狀態決定一個線程以什么樣的方式來終止自己。在默認情況下線程是非分離狀態的,這種情況下,原有的線程等待創建的線程結束。只有當pthread_join()函數返回時,創建的線程才算終止,才能釋放自己占用的系統資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。程序員應該根據自己的需要,選擇適當的分離狀態。所以如果我們在創建線程時就知道不需要了解線程的終止狀態,則可以pthread_attr_t結構中的detachstate線程屬性,讓線程以分離狀態啟動。

設置線程分離狀態的函數為pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二個參數可選為PTHREAD_CREATE_DETACHED(分離線程)和 PTHREAD _CREATE_JOINABLE(非分離線程)。這里要注意的一點是,如果設置一個線程為分離線程,而這個線程運行又非常快,它很可能在pthread_create函數返回之前就終止了,它終止以后就可能將線程號和系統資源移交給其他的線程使用,這樣調用pthread_create的線程就得到了錯誤的線程號。要避免這種情況可以采取一定的同步措施,最簡單的方法之一是可以在被創建的線程里調用pthread_cond_timewait函數,讓這個線程等待一會兒,留出足夠的時間讓函數pthread_create返回。設置一段等待時間,是在多線程編程里常用的方法。但是注意不要使用諸如wait()之類的函數,它們是使整個進程睡眠,並不能解決線程同步的問題。

另外一個可能常用的屬性是線程的優先級,它存放在結構sched_param中。用函數pthread_attr_getschedparam和函數pthread_attr_setschedparam進行存放,一般說來,我們總是先取優先級,對取得的值修改后再存放回去。

線程等待——正確處理線程終止

#include <pthread.h>

void pthread_exit(void *retval);

void pthread_join(pthread_t th,void *thread_return);//掛起等待th結束,*thread_return=retval;

int pthread_detach(pthread_t th);

如果線程處於joinable狀態,則只能只能被創建他的線程等待終止。

在Linux平台默認情況下,雖然各個線程之間是相互獨立的,一個線程的終止不會去通知或影響其他的線程。但是已經終止的線程的資源並不會隨着線程的終止而得到釋放,我們需要調用 pthread_join() 來獲得另一個線程的終止狀態並且釋放該線程所占的資源。(說明:線程處於joinable狀態下)

調用該函數的線程將掛起,等待 th 所表示的線程的結束。 thread_return 是指向線程 th 返回值的指針。需要注意的是 th 所表示的線程必須是 joinable 的,即處於非 detached(游離)狀態;並且只可以有唯一的一個線程對 th 調用 pthread_join() 。如果 th 處於 detached 狀態,那么對 th 的 pthread_join() 調用將返回錯誤。

如果不關心一個線程的結束狀態,那么也可以將一個線程設置為 detached 狀態,從而讓操作系統在該線程結束時來回收它所占的資源。將一個線程設置為detached 狀態可以通過兩種方式來實現。一種是調用 pthread_detach() 函數,可以將線程 th 設置為 detached 狀態。另一種方法是在創建線程時就將它設置為 detached 狀態,首先初始化一個線程屬性變量,然后將其設置為 detached 狀態,最后將它作為參數傳入線程創建函數 pthread_create(),這樣所創建出來的線程就直接處於 detached 狀態。

創建 detach 線程:

pthread_t tid;

pthread_attr_t attr;

pthread_attr_init(&attr);

pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

pthread_create(&tid, &attr, THREAD_FUNCTION, arg);

總之為了在使用 pthread 時避免線程的資源在線程結束時不能得到正確釋放,從而避免產生潛在的內存泄漏問題,在對待線程結束時,要確保該線程處於 detached 狀態,否着就需要調用 pthread_join() 函數來對其進行資源回收
 
原文鏈接:https://blog.csdn.net/huabiaochen/article/details/94717363


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM