一、線程的創建
頭文件
#include <pthread.h>
函數聲明
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
在一個線程中調用pthread_create函數創建新的線程後,當前線程從pthread_create處繼續往下執行,start_routine為新創建線程的入口函數,start_routine函數接收一個參數,是通過pthread_create的arg參數傳遞給它的,該參數的類型為void* ,這個指針按什麼類型解釋由調用者自己定義,start_routine的返回值類型也是void,這個指針的含義同樣由調用者自己定義,start_routine返回時,這個線程就退出了,其它線程可以調用pthread_join得到start_routine的返回值。
參數說明
第一個參數為指向線程標識符的指針。
第二個參數用來設置線程屬性,用於指定各種不同的線程屬性。
第三個參數是線程運行函數的起始地址,該函數只有一個萬能指針參數arg,如果需要向start_rtn函數傳遞的參數不止一個,那麼需要把這些參數放到一個結構中,然後把這個結構的地址作為arg的參數傳入。
最後一個參數是運行函數的參數。
返回值
若線程創建成功,則返回0,若線程創建失敗,則返回出錯編號,並且*thread中的內容是未定義的。
第一個簡單的線程程序
#include <stdio.h>
#include <pthread.h>
void printThread(const char *s)
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
printf("%s pid %u tid %u (0x%x)\n", s, (unsigned int) pid, (unsigned int) tid, (unsigned int) tid);
}
void* run(void* arg)
{
printThread("new thread: ");
return NULL;
}
int main(void)
{
pthread_t pt;
int err = pthread_create(&pt, NULL, run, NULL);
if (err != 0)
printf("can't create thread: %s\n", strerror(err));
printThread("main thread:");
pthread_join(pt, NULL);
return 0;
}
注意
因為pthread並非Linux系統的默認庫,而是POSIX線程庫。在Linux中將其作為一個庫來使用,因此加上 -lpthread(或-pthread)以顯式鏈接該庫。
$g++ main.cpp -lpthread -o main
$./main
二、pthread_join函數
函數聲明
int pthread_join(pthread_t thread, void **retval);
參數說明
thread: 線程標識符,即線程ID,標識唯一線程。
retval: 用戶定義的指針,用來存儲被等待線程的返回值。
描述
pthread_join函數,阻塞當前線程的執行,以等待thread指定的線程結束。當函數返回時,被等待線程的資源被收回。如果進程已經結束,那麼該函數會立即返回。並且thread指定的線程必須是joinable的,新創建的線程默認就是joinable的。
三、線程的兩種狀態:joinable(默認)和detached
joinable線程可以被其他線程回收,在被其他線程回收之前,它所占用的存儲器資源並不被釋放,而detached線程不能被其他線程回收,它占用的存儲器資源由系統自動釋放。
在默認情況下,線程是joinable的,只有當pthread_join函數返回時,創建的線程才算終止,才能釋放自己占用的系統資源,而detached線程沒有被其他線程等待,線程執行完畢立馬釋放系統資源。
設置線程狀態的函數pthread_attr_setdetachstate,函數聲明為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 之類的函數,它們是使整個進程睡眠,並不能解決線程同步的問題。
如果進程中的某個線程執行了pthread_detach(th),則th線程將處於DETACHED狀態,這使得th線程在結束運行時自行釋放所占用的內存資源,同時也無法由pthread_join()同步,pthread_detach()執行之後,對th請求pthread_join()將返回錯誤。
四、linux下多線程屬性設置
attr的缺省屬性值
pthread_attr_t attr;
初始化屬性
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_init 成功完成後將返回0,其他任何返回值都表示出現了錯誤,並將返回對應的值。
銷毀屬性
使用 pthread_attr_destroy(&attr) 刪除初始化期間分配的存儲空間,屬性對象將會無效,函數成功完成後將返回0,其他任何返回值都表示出現了錯誤,並將返回對應的值。