線程分離


未分離線程

在我們使用默認屬性創建一個線程的時候,線程是 joinable 的。 joinable 狀態的線程,必須在另一個線程中使用 pthread_join() 等待其結束, 如果一個 joinable 的線程在結束后,沒有使用 pthread_join() 進行操作, 這個線程就會變成"僵屍線程"。每個僵屍線程都會消耗一些系統資源, 當有太多的僵屍線程的時候,可能會導致創建線程失敗。

下面是一個創建僵屍線程的例子:

void* start_thread(void * arg) {
    //這個線程什么也不做,直接退出
    pthread_exit(NULL);
    return NULL;
}

int create_pthread(int n) {
    int try = 0;
    int i = 0;
    int err = 0;
    for(i = 0; i < n && try < 3; i++) {
        //當創建線程失敗的時候,嘗試3次
        pthread_t pt;
        err = pthread_create(&pt, NULL, start_thread, NULL);
        if(0 != err) {
            if(EAGAIN == err) {
                printf("errno : [EAGAIN]\n");
            }
            sleep(2);
            try ++;
        }
    }
    printf("create [%d] threads\n", i);

    return err;
}

int main(int argc, char * argv[]) {
    int n = 1 << 20;//最多創建 1M 個線程
    create_pthread(n);

    return 0;
}

 

上面代碼是創建僵屍線程的主要部分,把上面代碼編譯執行后, 輸出的結果是什么呢:

errno : [EAGAIN]
errno : [EAGAIN]
errno : [EAGAIN]
create [32754] threads

 

在上面的例子中,每個線程開始后,什么也不做,立刻就結束。 最后在我的環境下,只能創建 32754 個額外線程。

分離線程

當線程被設置為分離狀態后,線程結束時,它的資源會被系統自動的回收, 而不再需要在其它線程中對其進行 pthread_join() 操作。

下面我們對代碼做一些修改,讓每個線程在開始執行后,進行線程的分離, 然后看看執行后的結果。

void* start_thread(void * arg) {
    //注意,這里執行了線程的分離操作。線程分離也可以在線程創建的時候,
    //在屬性里面設置
    pthread_detach(pthread_self());

    pthread_exit(NULL);
    return NULL;
}

int create_pthread(int n) {
    int try = 0;
    int i = 0;
    int err = 0;
    for(i = 0; i < n && try < 3; i++) {
        pthread_t pt;
        err = pthread_create(&pt, NULL, start_thread, NULL);
        if(0 != err) {
            if(EAGAIN == err) {
                printf("errno : [EAGAIN]\n");
            }
            sleep(2);
            try ++;
        }
    }
    printf("create [%d] threads\n", i);

    return err;
}

int main(int argc, char * argv[]) {
    int n = 1 << 20;
    create_pthread(n);

    return 0;
}

 

執行結果如下:

create [1048576] threads

 

可以看到,最后成功創建了 1M 個線程。而沒有進行 pthread_join() 操作的時候,最多創建創建了 32754 個線程,原因就是沒有 detach 的線程,在其結束后,一些系統分配給它的資源還在被占用, 沒有被回收,導致無法再創建新的線程了。而 detach 的線程,在其結束后, 它的資源會被系統進行回收,然后進行再利用。所以這次才能創建 1M 的線程。

join 后的線程

在 man pthread_create 手冊中,可以看到關於一個線程的 detachd 狀態和 joinable 狀態的描述。其中說到,一個線程或者是 detachd 的狀態,這樣它結束后,資源會被系統 回收;或者是 joinable 狀態,並且在另一個線程里面被 pthread_join() 等待,pthread_join() 會回收它的資源。

我們可以再做個實驗,在創建完了一個 joinable 的線程后再使用 pthread_join() 等待它的結束, 回收它的資源,看看最多可以創建多少個線程。

void* start_thread(void * arg) {

    pthread_exit(NULL);
    return NULL;
}

int create_pthread(int n) {
    int try = 0;
    int i = 0;
    int err = 0;
    for(i = 0; i < n && try < 3; i++) {
        pthread_t pt;
        err = pthread_create(&pt, NULL, start_thread, NULL);
        if(0 != err) {
            if(EAGAIN == err) {
                printf("errno : [EAGAIN]\n");
            }
            sleep(2);
            try ++;
        }
        void *st = NULL;
        //這里等待一個線程的結束,並回收其資源
        err = pthread_join(pt, &st);
        if(0 != err) {
            printf("errno = [%d]\n", err);
            sleep(2);
            try ++;
        }
    }
    printf("create [%d] threads\n", i);

    return err;
}

int main(int argc, char * argv[]) {
    int n = 1 << 20;
    create_pthread(n);

    return 0;
}

 

執行結果:

create [1048576] threads

 

最后也是創建了 1M 個線程。

結論就是,在我們編寫多線程應用的時候,或者把一個線程的屬性設置為 detachd 的狀態,讓系統來回收它的資源;或者是 joinable 狀態,這樣就可以使用 pthread_join() 來阻塞的等待一個線程的結束,並回收其資源,並且pthread_join() 還會得到線程退出后的返回值,來判斷線程的退出狀態 。

 

同步地址:https://www.fengbohello.top/archives/linux-pthread-detach

 


免責聲明!

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



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