進程原語 | 線程原語 | 描述 |
fork | pthread_create | 創建新的控制流 |
exit | pthread_exit | 從現有的控制流中退出 |
waitpid | pthread_join | 從控制流中得到退出狀態 |
atexit | pthread_cancel_push | 注冊在退出控制流時調用的函數 |
getpid | pthread_self | 獲取控制流的ID |
abort | pthread_cancel | 請深圳市控制流的非正常退出 |
pthread_create
int pthread_create(pthread_t *thread, pthread_addr_t *arr,void* (*start_routine)(void *), void *arg);
- thread :用於返回創建的線程的ID
- arr : 用於指定的被創建的線程的屬性,上面的函數中使用NULL,表示使用默認的屬性
- start_routine : 這是一個函數指針,指向線程被創建后要調用的函數
- arg : 用於給線程傳遞參數,在本例中沒有傳遞參數,所以使用了NULL
線程創建時並不能保證哪個線程會先運行:是新創建的線程還是調用線程。新創建的線程可以訪問進程的地址空間,
並且繼承調用線程的浮點環境和信號屏蔽字,但是該線程的未決信號集被消除。
單個線程可以通過三種方式退出,在不終止整個進程的情況下停止它的控制流。
(1)線程只是從啟動全程中返回,返回值是線程的退出碼。
(2)線程可以被同一進程中的其他線程取消
(3)線程調用pthread_exit
void pthread_exit(void *rval_ptr)
rval_ptr是一個無類型指針,與傳給啟動例程的單個參數類似。進程中的其他線程可以通過調用pthread_join函數訪問到這個指針。
int pthread_join(pthread_t thread,void **rval_ptr);
成功返回0,失敗返回錯誤編號
調用線程將一直阻塞,直到指定的線程調用pthread_exit,從啟動例程中返回或者被取消。
如果線程只是從它的啟動例程返回,rval_ptr將包含返回碼。如果線程被取消,由rval_ptr指定的內存單元被置為PTHREAH_CANCELED.
可以通過調用pthread_join自動把線程置於分離狀態,這樣資源就可以恢復。如果線程已經處於分離狀態,pthread_join調用就會失敗,返回EINVAL.
如果對線程的返回值並不感興趣,可以把rval_ptr置為NULL。在這種情況下,調用pthread_join函數將等待指定的線程停止,但並不獲取線程的終止狀態。
在 調用線程的棧上分配了該結構,那么其他的線程在使用這個結構進內存可能已經改變了。又如,線程在自己的棧上分配了一個結構然后把指向這個結構的指針傳給 pthread_exit,那么當調用pthread_join的線程試圖使用該結構時,這個棧有可能已經被撤消,這塊內存也已另作他用。
例如:#include <stdlib.h>
void pthread_cleanup_push(void (*rtn)(void *),void *arg);
void pthread_cleanup_pop(int execute);
當線程執行以下動作時調用清理函數,調用參數為arg,清理函數rtn的調用順序是由pthread_cleanup_push函數來安排的。
1.調用pthread_exit時。2.響應取消請求時。3.用非零execute參數調用pthread_cleanup_pop時。
如果execute參數置為0,清理函數將不被調用。無論哪種情況,pthread_cleanup_pop都將刪除上次pthread_clean_push調用建立的清理處理程序。
實例:
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <pthread.h> 4 5 void cleanup(void *arg) 6 { 7 printf("cleanup: %s\n", (char *)arg); 8 } 9 10 void *thr_fn1(void *arg) 11 { 12 printf("thread 1 start\n"); 13 pthread_cleanup_push(cleanup, "thread 1 first handler"); 14 pthread_cleanup_push(cleanup, "thread 1 second handler"); 15 printf("thread 1 push complete\n"); 16 if (arg) 17 return((void *)1); 18 // pthread_exit((void *)2); 19 20 pthread_cleanup_pop(0); 21 pthread_cleanup_pop(0); 22 // return((void *)1); 23 pthread_exit((void *)2); 24 25 } 26 27 void *thr_fn2(void *arg) 28 { 29 printf("thread 2 start\n"); 30 pthread_cleanup_push(cleanup, "thread 2 first handler"); 31 pthread_cleanup_push(cleanup, "thread 2 second handler"); 32 printf("thread 2 push complete\n"); 33 if (arg) 34 pthread_exit((void *)2); 35 pthread_cleanup_pop(0); 36 pthread_cleanup_pop(0); 37 pthread_exit((void *)2); 38 } 39 40 int main(void) 41 { 42 int err; 43 pthread_t tid1, tid2; 44 void *tret; 45 46 err = pthread_create(&tid1, NULL, thr_fn1, (void *)1); 47 if (err != 0) 48 printf("can't create thread 1: %c\n", strerror(err)); 49 err = pthread_create(&tid2, NULL, thr_fn2, (void *)1); 50 if (err != 0) 51 printf("can't create thread 2: %c\n", strerror(err)); 52 err = pthread_join(tid1, &tret); 53 if (err != 0) 54 printf("can't join with thread 1: %c\n", strerror(err)); 55 printf("thread 1 exit code %d\n", (int)tret); 56 err = pthread_join(tid2, &tret); 57 if (err != 0) 58 printf("can't join with thread 2: %c\n", strerror(err)); 59 printf("thread 2 exit code %d\n", (int)tret); 60 exit(0); 61 }