線程是作業系統能夠進行獨立排程和分派的基本機關。在類UNIX系統中,通常情況下一個程序可以被看做隻有一個控制線程。一個線程指的是程序中一個單一順序的控制流,一個程序中可以并發多個線程,每個線程并行執行不同的任務。
同一程序中的多個線程将共享該程序中的全部系統資源,包括可執行的程式文本、虛拟位址空間、全局記憶體、堆記憶體、檔案描述符和信号處理等。但同一程序中的多個線程有各自的調用棧,自己的寄存器上下文,線程ID以及線程私有資料。
這裡對POSIX線程操作做一些簡單描述記錄,并結合一個例子,深化了解。最後對與線程相關的一些函數做個大概的介紹。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <errno.h>
#define handle_error_en(err, msg) \
do { errno = err; perror(msg); exit(EXIT_FAILURE); } while (0)
static int done = 0;
static int cleanup_pop_arg = 0;
static int cnt = 0;
static void * cleanup_handler()
{
printf("called cleanup handler\n");
cnt = 0;
return NULL;
}
void * thread_start(void *arg)
{
time_t start, curr;
printf("new thread started\n");
printf("thread id is: %lu\n", pthread_self()); //擷取線程自己的ID
pthread_cleanup_push(cleanup_handler, NULL); //設定線程退出時将調用的清理函數
curr = start = time(NULL);
while (!done) {
pthread_testcancel(); //設定響應其他線程的取消申請時,具體的退出點
if (curr < time(NULL)) {
curr = time(NULL);
printf("cnt = %d\n", cnt);
cnt++;
}
}
pthread_cleanup_pop(cleanup_pop_arg); //調用cleanup_pop_arg非零值時,會調用 清理函數cleanup_handler
// if (done)
// pthread_exit((void *)1); //調用pthread_exit()時,線程會調用 清理函數
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t thr;
int err;
void *res;
err = pthread_create(&thr, NULL, thread_start, NULL); //建立新線程
if (err != 0)
handle_error_en(err, "pthread_create");
sleep(2);
if (argc > 1) {
if (argc > 2)
cleanup_pop_arg = atoi(argv[2]);
done = 1;
}
else {
printf("canceling thread\n");
err = pthread_cancel(thr); //對建立的線程發出取消請求
if (err != 0)
handle_error_en(err, "pthread_cancel");
}
err = pthread_join(thr, &res); //擷取線程的退出狀态,主線程會阻塞
if (err != 0)
handle_error_en(err, "pthread_join");
if (res == PTHREAD_CANCELED)
printf("thread was canceled; cnt = %d\n", cnt);
else
printf("thread terminated normally; cnt = %d\n", cnt);
exit(EXIT_SUCCESS);
}
------------------------------------------------------------------------
對以上這個小例子做測試:
[[email protected] ~]$ ./cleanup2 // argc == 1
new thread started
thread id is: 140498886080256
cnt = 0
cnt = 1
canceling thread
called cleanup handler
thread was canceled; cnt = 0
[[email protected] ~]$ ./cleanup2 1 // argc == 2
new thread started
thread id is: 139745109219072
cnt = 0
cnt = 1
thread terminated normally; cnt = 2
[[email protected] ~]$ ./cleanup2 1 1 // argc == 3 argv[2] = 1 非零值
new thread started
thread id is: 140498886080256
cnt = 0
cnt = 1
canceling thread
called cleanup handler
thread was canceled; cnt = 0
[us[email protected] ~]$ ./cleanup2 1 0 // argc == 3 argv[2] = 0 零值
new thread started
thread id is: 139975075624704
cnt = 0
cnt = 1
thread terminated normally; cnt = 2
--------------------------------------------------------------------------
線程建立
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg)
參數:
pthread_t *thread_id : 指向的記憶體區域用于儲存新建立的線程ID
const pthread_attr_t *attr :用于設定線程的屬性,預設設定為NULL
void *(*start_routine) (void *) :這是一個函數指針,新建立的線程将從這個函數位址開始執行
void *arg :無類型指針參數,傳遞給start_routine
傳回值:
線程被成功建立 傳回0,失敗放回錯誤碼
擷取線程ID
pthread_t pthread_self(void)
傳回值:
線程自己的ID
擷取線程退出狀态
int pthread_join(pthread_t thread, void **retval)
參數:
pthread_t thread_id : 要擷取退出狀态的線程ID
void **retval : 線程的退出碼。建立的線程正常傳回,這裡會儲存線程的傳回碼,如果線程時被取消的(調用pthread_cancel),retval指向的記憶體單元被置為PTHREAD_CANCELED
傳回值:
線程被成功建立 傳回0,失敗放回錯誤碼
線程退出
void pthread_exit(void *retval)
參數:
void *retval :如果線程是可連接配接的,會通過retval傳回一個值,這個值可以用pthread_join擷取
申請取消其他線程
int pthread_cancel(pthread_t thread)
參數:
pthread_t thread_id : 需要申請取消的線程ID
傳回值:
成功:0, 失敗:錯誤碼
設定和删除線程退出時需要執行的函數,這兩個函數通常都是成對出現
void pthread_cleanup_push(void (*routine)(void *), void *arg)
參數:
void (*routine)(void *) :注冊線程退出時需要調用的線程清理程式
void *arg : 傳遞給線程清理程式的參數
void pthread_cleanup_pop(int execute)
參數:
int execute :非零值會調用線程清理程式,設定為0,線程清理程式不會被調用。
備注:線程調用pthread_exit()和響應其他線程的申請取消請求的情況下,任然會調用線程清理程式,但不管是哪種方式都會删除掉有pthread_cleanup_push設定的線程清理程式。