標籤:線程 linux pthread_exit pthread_cancel pthread_create
線程原語
線程概念
線程(thread),有時被稱為輕量級進程(Lightweight Process,LWP),是程式執行流的最小單元。一個標準的線程由線程ID,當前指令指標(PC),寄存器集合和堆棧組成。更多詳細解釋看百度百科:線程。
在Linux shell下通過命令 $ ps -Lf pid 查看指定pid號下的所有線程。
線程之間的共用與非共用
這裡的線程是指同一進程下的線程。
共用:
1.檔案描述符表
2.每種訊號的處理方式
3.當前工作目錄
4.使用者ID和組ID
5.記憶體位址空間
非共用:
1.線程id
2.處理器現場和棧指標(核心棧)
3.獨立的棧空間(使用者空間棧)
4.errno變數
5.訊號屏蔽字
6.調度優先順序
線程原語
通過命令 $ man -k pthread 查看系統下與線程有關的所有函數。
一般的,把main函數稱作主線程或主控線程,其它線程都稱作是子線程。
建立線程
#include<pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
pthread_t *thread:傳遞一個pthread_t變數地址進來,用於儲存新線程的tid(線程ID)
const pthread_attr_t *attr:線程屬性設定,如使用預設屬性,則傳NULL
void *(*start_routine)(void *):函數指標,指向新線程應該載入執行的函數模組
void *arg:指定線程將要載入調用的那個函數的參數
傳回值:成功返回0,失敗返回錯誤號碼。以前學過的系統函數都是成功返回0,失敗返回-1,而錯誤號碼儲存在全域變數errno中,而pthread庫的函數都是通過傳回值返回錯誤號碼,雖然每個線程也都有一個errno,但這是為了相容其它函數介面而提供的,pthread庫本身並不使用它,通過傳回值返回錯誤碼更加清晰。
Compile and link with -lpthread.
typedef unsigned long int pthread_t; //在不同的系統中pthread_t可能會有不同的實現
結束線程
如果需要只終止某個線程而不終止整個進程,可以有三種方法:
1.return。這種方法對主控線程不適用,從main函數return相當於調用exit。
2.一個線程可以調用pthread_cancel終止同一進程中的另一個線程。
#include <pthread.h>int pthread_cancel(pthread_t thread);
被取消的線程,退出值,定義在Linux的pthread庫中常數PTHREAD_CANCELED的值是-1。可以在標頭檔pthread.h中找到它的定義:#define PTHREAD_CANCELED ((void *) -1)。也就是說,被pthread_cancel結束的線程,退出值,都是-1。
同一進程的線程間,pthread_cancel向另一線程發終止訊號。系統並不會馬上關閉被取消線程,只有在被取消線程下次系統調用時,才會真正結束線程。或調用pthread_testcancel,讓核心去檢測是否需要取消當前線程。
3.線程可以調用pthread_exit終止自己。
#include <pthread.h>void pthread_exit(void *retval);void *retval:線程退出時傳遞出的參數,可以是退出值或地址,如是地址時,不能是線程內部申請的局部地址。
在任何地方調用exit,都會使整個進程退出。
線程id
#include <pthread.h>pthread_t pthread_self(void);RETURN VALUEThis function always succeeds, returning the calling thread’s ID.
線上程中使用pthread_self,擷取線程id。
回收線程
#include <pthread.h>int pthread_join(pthread_t thread, void **retval);pthread_t thread:回收線程的tidvoid **retval:接收退出線程傳遞出的傳回值傳回值:成功返回0,失敗返回錯誤號碼
同進程類似,線程退出後,同樣需要進行回收,所以pthread_join類似於wait。調用該函數的線程將掛起等待,直到id為thread的線程終止。thread線程以不同的方法終止,通過pthread_join得到的終止狀態是不同的,總結如下:
- 如果thread線程通過return返回,retval所指向的單元裡存放的是thread線程函數的傳回值。
- 如果thread線程被別的線程調用pthread_cancel異常終止掉,retval所指向的單元裡存放的是常數PTHREAD_CANCELED。
- 如果thread線程是自己調用pthread_exit終止的,retval所指向的單元存放的是傳給pthread_exit的參數。
如果對thread線程的終止狀態不感興趣,可以傳NULL給retval參數。
程式碼範例使用return和pthread_exit結束進程
//thread_exit.c#include <stdio.h>#include <unistd.h>#include <pthread.h>void *fun_1(void *argv){printf("Hello %s,my thread id is %x\n", (char*)argv, pthread_self());sleep(1);//pthread_exit((void*)1);return (void*)1;}void *fun_2(void *argv){printf("Hello %c, my thread id is %x\n", (char)argv, pthread_self());sleep(2);pthread_exit((void*)"David");}int main(void){int *ret1;char *ret2;pthread_t tid1, tid2;pthread_create(&tid1, NULL, fun_1, (void*)"zhangxiang");pthread_create(&tid2, NULL, fun_2, (void*)‘D‘);pthread_join(tid1, (void*)&ret1);pthread_join(tid2, (void*)&ret2);printf("thread %x exit with %x\n", tid1, ret1);printf("thread %x exit with %s\n", tid2, ret2);return 0;}$ gcc thread_exit.c -lpthread$ ./a.outHello D, my thread id is 745e9700Hello zhangxiang, my thread id is 74fea700thread 74fea700 exit with 1thread 745e9700 exit with David
使用pthread_cancel終止另一個線程
//thread_cancel.c#include <stdio.h>#include <pthread.h>void *fun(void *argv){printf("thread %x running\n", pthread_self());pthread_exit((void*)0);}int main(void){pthread_t tid;void *ret;pthread_create(&tid, NULL, fun, NULL);pthread_join(tid, &ret);printf("thread %x exit with %d\n", tid, (int)ret);pthread_create(&tid, NULL, fun, NULL);pthread_cancel(tid);pthread_join(tid, &ret);printf("thread %x exit with %d\n", tid, (int)ret);return 0;}$ gcc thread_cancel.c -lpthread$ a.outthread 96da9700 runningthread 96da9700 exit with 0thread 96da9700 runningthread 96da9700 exit with -1
既可以在主線程中使用pthread_cancel終止子線程,也可以在子線程中終止另一個子線程。
CCPP Blog 目錄
著作權聲明:本文為博主原創文章,轉載,請註明出處。
linux系統編程:線程原語