線程控制
POSIX線程庫
- 與線程有關的函數構成了一個完整的系列,絕大多數函數的名字都是以“pthread_”打頭的
- 要使用這些庫函數,要引入頭文件 pthread.h
- 鏈接這些線程函數庫時要使用編譯器命令“-lpthread” 選項
創建線程:
int pthread_create(pthread_t* thread, const pthread_attr_t*
attr, void* (*start_routine)(void*), void* arg)
參數:
thread:返回線程ID
attr:設置線程屬性,attr = NULL,表示使用默認屬性
start_routine:是個函數地址,線程啓動後要執行的函數
arg:傳給線程啓動函數的參數
返回值:成功返回0;失敗返回錯誤碼
舉個例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *rout(void *arg){
(void)arg;
while(1){
printf("I am thread 1\n");
sleep(1);
}
}
int main(void){
pthread_t tid;
int ret;
if((ret = pthread_create(&tid, NULL, rout, NULL)) != 0){
fprintf(stderr, "pthread_create:%s\n", strerror(ret));
exit(EXIT_FAILURE);
}
while(1){
printf("I am main thread\n");
sleep(1);
}
}
進程ID和線程ID
- 在Linux中,目前線程實現是Native POSIX Thread Libaray,簡稱NPTL。在這種實現下,線程又被稱爲輕量級進程,每一個用戶態的線程,在內核中對應一個調度實體,也擁有自己的進程描述符(task_struct結構體)。
- 沒有線程之前,一個進程對應內核裏一個進程描述符,對應一個進程ID。但是引入線程概念之後,一個用戶進程下管轄N個用戶態線程,每個線程作爲一個獨立的調度實體在內核態都有自己的進程描述符,進程和內核的描述符一下變成1 : N的關係,POSIX標準又要求進程內所有線程調用getpid函數時返回相同的進程ID,如何解決上述問題呢?
- Linux引入了線程組的概念。
struct task_struct {
...
pid_t pid;
pid_t tgid;
...
struct task_struct* group_leader;
...
struct list_head thread_group;
...
- 多線程的進程,又被稱爲線程組,線程組內的的每一個線程在內核中都有一個進程描述符與之對應。進程描述符中的pid對應線程id;進程描述符中的tgid,含義是Thread Group ID,該值對應的是用戶層面的進程ID。
線程ID及進程地址空間佈局
- pthread_create函數會產生一個線程ID,存放在第一個參數指向的地址中。該線程ID和前面所說的線程ID不一樣。
- 前面的線程ID屬於進程調度的範疇。因爲線程是輕量級進程,是操作系統調度器的最小單位,所以需要一個數值來唯一標識一個線程。
- pthread_create函數產生並標記在第一個參數指向的地址中的線程ID中,屬於NPTL線程庫的範疇。線程庫的後續操作,就是根據該線程ID來操作線程的。
- NPTL提供了pthread_self函數獲得自身ID。
pthread_t pthread_self(void)
線程終止
如果要終止某一個進程而不終止整個進程,可以有三種方法:
- 從線程函數return。這種方法對主線程不適用,從main函數return相當於調用exit.
- 線程可以調用pthread_exit終止自己
- 一個線程可以調用pthread_cancle終止同一個進程中的另外一個線程。
Pthread_exit函數
功能:線程終止
原型: void pthread_exit(void* value_ptr)
參數: value_ptr:value_ptr不要指向一個局部變量
返回值: 無返回值
pthread_cancel函數
功能:取消一個執行中的線程
原型: int pthread_cancle(pthread_t thread);
參數:thread:線程ID
返回值:成功返回0;失敗返回錯誤碼
線程等待與分離
線程等待
爲什麼線程需要等待?
- 已經退出的線程,其空間沒有被釋放,仍然在進程地址空間內。
- 創建新的線程不會複用剛纔退出線程的地址空間。
功能:等待線程結束
原型:
int pthread_join(pthread_t thread, void **value_ptr)
參數:
thread:線程ID
value_ptr:它指向一個指針,該指針指向線程的返回值。
返回值:成功返回0;失敗返回錯誤碼。
調用該函數的線程將掛起等待,直到id爲thread的線程終止。thread通過不同方法終止,通過phread_join得到的終止碼是不同的。
1.如果thread線程通過return返回,value_ptr所指向的單元裏存放的是thread線程函數的返回值。
2.如果thread線程被別的函數調用phread_cancle異常終止掉,value_ptr所指向的單元裏存放的是常數PThREAD_CANCLEED
3.如果thread線程是自己調用pthread_exit ()終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數。
4.如果對thread線程的終止狀態不感興趣可以穿參數NULL