天天看點

pthread線程程式設計基礎

線程是作業系統能夠進行獨立排程和分派的基本機關。在類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設定的線程清理程式。

繼續閱讀