pthread_joinhe和pthread_detach

首先看一下兩個函數的定義:

int pthread_join(pthread_t tid, void **status);

參數tid 是希望等待的線程的線程號,status 是指向線程返回值的指針,線程的返回值就是pthread_exit 中的value_ptr 參數,或者是return語句中的返回值。該函數可用於線程間的同步。

int pthread_detach( pthread_t pid );

參數tid 是希望等待的線程的線程號, 把指定的線程轉變爲脫離狀態。一個線程或者是可匯合的(joinable,缺省值),或者是脫離的(detached)。當一個可匯合的線程終止時,它的線程ID和退出狀態將留到另一個線程對它調用pthread_join。脫離線程卻象守護進程:當它們終止的時,所有相關資源都被釋放,我們不能等待它們終止。如果一個線程需要知道另一個線程什麼時候終止,那就最好等待第二個線程的可匯合狀態。

下面通過例子說明:

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

#define THREAD_NUMBER 2
int retval_hello1 = 1, retval_hello2 = 2;

void *hello1(void *arg)
{
    char *hello_str = (char *)arg;
    sleep(5);
    printf("%s\r\n", hello_str);
    pthread_exit(&retval_hello1);
}

void *hello2(void *arg)
{
    char *hello_str = (char *)arg;
    // sleep(1);
    printf("%s\r\n", hello_str);
    pthread_exit(&retval_hello2);
}

int main(int argc, char *argv[])
{
    int i;
    int ret_val;
    int *retval_hello[2];

    pthread_t pt[THREAD_NUMBER];
    const char *arg[THREAD_NUMBER];
    arg[0] = "hello world from thread1";
    arg[1] = "hello world from thread2";

    printf("Begin to create threads...\r\n");
    ret_val = pthread_create(&pt[0], NULL, hello1, (void *)arg[0]);
    if (ret_val != 0 )
    {
        printf("pthread_create error!\r\n");
        exit(1);
    }

    ret_val = pthread_create(&pt[1], NULL, hello2, (void *)arg[1]);
    if (ret_val != 0 )
    {
        printf("pthread_create error!\r\n");
        exit(1);
    }

    printf("Begin to wait for threads...\r\n");
    for(i = 0; i < THREAD_NUMBER; i++)
    {
        ret_val = pthread_join(pt[i], (void **)&retval_hello[i]);
        if (ret_val != 0)
        {
            printf("pthread_join error!\r\n");
            exit(1);
        }
        else
        {
            printf("return value is %d\n", *retval_hello[i]);
        }
    }
    printf("Now, the main thread returns.\r\n");
    return 0;
}

執行結果爲:

Begin to create threads...
Begin to wait for threads...
hello world from thread2
hello world from thread1
return value is 1
return value is 2
Now, the main thread returns.

線程1,2的執行順序可以通過sleep來調節,但是主線程必須在子線程完成之後才能執行,即打印”Now, the main thread returns.“。此外,因爲調用pthread_join()的順序,必定是線程1先執行“return value is xx”,不管線程2是否先執行完。

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

#define THREAD_NUMBER 2
int retval_hello1 = 1, retval_hello2 = 2;

void *hello1(void *arg)
{
    char *hello_str = (char *)arg;
    sleep(2);
    printf("%s\r\n", hello_str);
    pthread_exit(&retval_hello1);
}

void *hello2(void *arg)
{
    char *hello_str = (char *)arg;
    sleep(1);
    printf("%s\r\n", hello_str);
    pthread_exit(&retval_hello2);
}

int main(int argc, char *argv[])
{
    int i;
    int ret_val;
    int *retval_hello[2];

    pthread_t pt[THREAD_NUMBER];
    const char *arg[THREAD_NUMBER];
    arg[0] = "hello world from thread1";
    arg[1] = "hello world from thread2";

    printf("Begin to create threads...\r\n");
    ret_val = pthread_create(&pt[0], NULL, hello1, (void *)arg[0]);
    if (ret_val != 0 )
    {
        printf("pthread_create error!\r\n");
        exit(1);
    }

    ret_val = pthread_create(&pt[1], NULL, hello2, (void *)arg[1]);
    if (ret_val != 0 )
    {
        printf("pthread_create error!\r\n");
        exit(1);
    }

    printf("Begin to wait for threads...\r\n");
    for(i = 0; i < THREAD_NUMBER; i++)
    {
        ret_val = pthread_detach(pt[i]);
        if (ret_val != 0)
        {
            printf("pthread_join error!\r\n");
            exit(1);
        }
    }
    printf("Now, the main thread returns.\r\n");

    sleep(5);

    return 0;
}

執行結果爲

Begin to create threads...
Begin to wait for threads...
Now, the main thread returns.

線程1,2沒有執行(也可能執行),因爲子線程爲可分離的,主線程在執行完之後即將進程銷燬,資源收回,導致子線程未運行。可以在return 0 語句之前加入sleep(5),這樣執行結果爲

Begin to create threads...
Begin to wait for threads...
Now, the main thread returns.
hello world from thread2
hello world from thread1

所以,pthread_join()會掛起父線程,直至子線程完成纔可以執行後面的代碼,此外,一個PTHREAD_CREATE_JOINABLE狀態的子線程不會自動釋放該線程的內存資源,包括線程描述符和其使用的棧;而主線程調用pthread_detach()時,無需等待子線程的完成,它可以立即執行後面的代碼,當然,也有可能主線程執行完之後銷燬進程,導致子線程未能執行,此外,一個PTHREAD_CREATE_DETACH狀態的子線程擁有自我回收內存資源的功能。

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