Linux中主線程和子線程的終止次序

Linux中pthread是我們進行多線程併發時經常使用的,pthread創建的子線程和主線程的終止順序有什麼樣的關係,下面通過代碼來總結下。

在代碼測試前,先說下結論:

      (1)主線程和子線程之間沒有必然的退出次序關係。主線程退出,子線程可以繼續執行;子線程退出,主線程也可以繼續執行。

      (2)程序加載到內存中執行的時候,進程就會生成一個主線程。雖然主線程和子線程之間沒有必然的退出次序關係,但是如果進程終止,那麼進程下所有的線程都會終止。

1. 子線程先終止,主線程後終止。 

代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

void printids(const char *str) {
    pid_t pid = getpid();
    pthread_t tid = pthread_self();
    printf("%s pid: %u, tid: %u, tid in 0x presentation: 0x%x.\n",str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
}

void *func(void *arg) {
    printids("descendant thread");
    pthread_detach(pthread_self());
    return ((void*)0);
}

int main(void) {
    pthread_t myid;
    pthread_create(&myid, NULL, func, NULL);
    
    sleep(1);  // 等待子線程先退出
    printids("main thread");

    return 0;
}

運行結果: 

2. 進程結束,所有線程都終止。 

代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

void printids(const char *str) {
    pid_t pid = getpid();
    pthread_t tid = pthread_self();
    printf("%s pid: %u, tid: %u, tid in 0x presentation: 0x%x.\n",str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
}

void *func(void *arg) {
    sleep(1);  // 等待主線程先退出
    printids("descendant thread");
    pthread_detach(pthread_self());
    return ((void*)0);
}

int main(void) {
    pthread_t myid;
    pthread_create(&myid, NULL, func, NULL);
    
    // sleep(1);  // 等待子線程先退出
    printids("main thread");

    return 0;  //進程退出,系統清除所有資源
}

運行結果: 
 
此時,由於進程退出,該進程中的所有線程都會終止,系統回收所有的資源,因此子線程還沒來得及輸出pid和tid就已經退出了。

3、主線程先終止,子線程後終止。

主線程需要調用 pthread_exit() 終止,注意和示例2的區別。

代碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

void printids(const char *str) {
    pid_t pid = getpid();
    pthread_t tid = pthread_self();
    printf("%s pid: %u, tid: %u, tid in 0x presentation: 0x%x.\n",str, (unsigned int)pid, (unsigned int)tid, (unsigned int)tid);
}

void *func(void *arg) {
    sleep(1);  // 等待主線程先退出
    printids("descendant thread");
    pthread_detach(pthread_self());
    return ((void*)0);
}

int main(void) {
    pthread_t myid;
    pthread_create(&myid, NULL, func, NULL);
    
    printids("main thread");
    pthread_exit(NULL);

    return 0;  //進程退出,系統清除所有資源
}

運行結果:

When you program with POSIX Threads API,there is one thing about pthread_exit() that you may ignore for 
mistake. Insubroutines that complete normally, there is nothing special you have to dounless you want 
to pass a return code back using pthread_exit(). The completionwon’t affect the other threads which 
were created by the main thread of thissubroutine. However, in main(), when the code has been executed 
to the end,there could leave a choice for you. If you want to kill all the threads that main() created 
before, you can dispense with calling any functions. But if you want to keep the process and all the 
other threadsexcept for the main thread alive after the exit of main(), then you can call pthread_exit() 
to realize it. And any files opened inside the main thread will remain openafter its termination.

主進程退出後,子進程並沒有退出,而是繼續執行。

 

POSIX標準定義: 

按照POSIX標準定義,當主線程在子線程終止之前調用pthread_exit()時,子線程是不會退出的。

注意:這裏在main函數中調用pthread_exit()只會是主線程退出,而進程並未退出。參照CSAPP中的講解,當主線程執行pthread_exit()之後,主線程終止,進程並未終止,而是等待所有的子線程終止之後再結束。

總結: 

一個線程的終止不會影響到另外一個線程。但是進程結束,該進程下所有線程也會立馬終止,所有資源會被回收。

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