在《線程初識》中,我們已經了解到了建立線程的函數
pthread_create
函數。本篇打算詳細介紹一下
pthread_create
函數,另外還有線程終止及相關的函數。
1. 線程建立
- 函數原型
typedef void *(*start_routine) (void *);
int pthread_create(pthread_t *thread, const
- pthread_t 類型是線程 id 的類型,它可能是個整數(大多數是這樣),也可能是結構體,這取決于具體實作。thread 參數是一個傳出參數,它主要用來接收被建立的線程的 id 号。線上程執行過程中調用函數
函數,可以擷取到自己的線程 id 号。pthread_self
- pthread_attr_t 類型是用來儲存線程屬性的結構體,通常參數 attr 可以傳 NULL,表示建立具有預設屬性的線程。有關線程的屬性結構體,後文會作具體講解。
- start_routine 是用來聲明函數型如
這樣的函數的,它是線程過程函數。線程被建立後,一旦被排程,就會進入到函數 th_fn 中執行。void* th_fn(void* arg)
- 最後一個參數 arg,是線程過程函數 th_fn 的參數。
-
函數的傳回值是一個錯誤碼,傳回 0 表示成功。和其它 POSIX 函數不同的是,pthread_create
函數執行錯誤并不會設定 errno 變量。pthread_create
2. 線程終止
2.1 線程終止方式
線程的終止包括兩大類,主動終止和被動終止。
- 主動終止
- 線程過程函數執行
正常傳回,傳回值是線程的退出碼return
- 線種過程函數執行
函數退出,其參數是線程退出碼pthread_exit
- 被動終止
- 在其它線程中調用
函數pthread_cancel
- 任意線程調用 exit、_Exit 或者 _exit 導緻整個程序終止
2.2 pthread_exit 函數
pthread_exit 函數原型
void pthread_exit(void
該函數的參數是線程的退出碼,它是無類型的指針。通過函數
pthread_join
可以擷取到這個指針的值。該函數有點類似于我們之前學習的 waitpid 函數,它可以回收線程所使用的資源。
int pthread_join(pthread_t tid, void
調用
pthread_join
會阻塞目前線程,直到指定的線程 tid 傳回(return)、執行
pthread_exit
或者被其它線程取消(
pthread_cancel
)。rval_ptr 是一個輸出參數,它用來接收線程退出碼(是一個 void* 類型)。
2.3 pthread_cancel 函數
int
預設情況下,該函數的效果相當于線上程 tid 中調用
pthread_exit((void*)PTHREAD_CANCEL)
函數。
3. 示例(線程主動退出)
- 程式代碼
// threadexit.c
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ERR(name,err) do{printf("%s:%s\n",#name,strerror(err));exit(-1);}while(0);
void* th_fn1(void* arg) {
puts("thread 1 returning");
return (void*)10;
}
void* th_fn2(void* arg) {
puts("thread 2 exiting");
pthread_exit((void*)20);
puts("thread 2 exited");
}
int main() {
pthread_t tid1, tid2;
int err;
void* ret;
err = pthread_create(&tid1, NULL, th_fn1, NULL);
if (err != 0) ERR(pthread_create1, err);
err = pthread_create(&tid2, NULL, th_fn2, NULL);
if (err != 0) ERR(pthread_create2, err);
sleep(2);
// 主線程阻塞直到線程 tid1 退出
err = pthread_join(tid1, &ret);
if (err != 0) ERR(pthread_join1, err);
printf("thread 1 exit code %d\n", (int)ret);
// 主線程阻塞直到線程 tid2 退出
err = pthread_join(tid2, &ret);
if (err != 0) ERR(pthread_join2, err);
printf("thread 2 exit code %d\n", (int)ret);
return 0;
}
- 編譯和運作
$ gcc threadexit.c -o threadexit -lpthread
$ ./threadexit
- 運作結果
圖1 線程主動終止
4. 示例(被動終止)
- 代碼
// threadcancel.c
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ERR(name,err) do{printf("%s:%s\n",#name,strerror(err));exit(-1);}while(0);
void* th_fn1(void* arg) {
while(1) {
puts("thread 1 running");
sleep(1);
}
return (void*)10;
}
void* th_fn2(void* arg) {
while(1) {
puts("thread 2 running");
sleep(1);
}
pthread_exit((void*)20);
}
int main() {
pthread_t tid1, tid2;
int err;
void* ret;
err = pthread_create(&tid1, NULL, th_fn1, NULL);
if (err != 0) ERR(pthread_create1, err);
err = pthread_create(&tid2, NULL, th_fn2, NULL);
if (err != 0) ERR(pthread_create2, err);
sleep(5);
// 通知 tid1 和 tid2 退出。
pthread_cancel(tid1);
pthread_cancel(tid2);
err = pthread_join(tid1, &ret);
// 線程退出碼都是 PTHREAD_CANCELED
printf("PTHREAD_CANCELED = %d\n", (int)PTHREAD_CANCELED);
if (err != 0) ERR(pthread_join1, err);
printf("thread 1 exit code %d\n", (int)ret);
err = pthread_join(tid2, &ret);
if (err != 0) ERR(pthread_join2, err);
printf("thread 2 exit code %d\n", (int)ret);
return 0;
}
- 編譯和運作
$ gcc threadcancel.c -o threadcancel -lpthread
$ ./threadcancel
- 運作結果
5. 總結
- 掌握線程建立函數
- 掌握線程終止的幾種方式