線程原語編程
pthread_create
建立線程多線程
#include <pthread.h>函數
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,spa
void *(*start_routine) (void *), void *arg);線程
pthread_t *thread 傳出參數,返回線程tid
const pthread_attr_t *attr 設置線程屬性,例如:線程用戶棧大小,線程優先級
void *(*start_routine) (void *) 線程的處理動做 函數指針void*fun(void*)
void *arg 線程處理動做的參數指針
pthread_self
獲取調用線程tidcode
#include <pthread.h>blog
pthread_t pthread_self(void);進程
思考:pthread_self與tid等價嗎?事件
不等價,應爲pthread_self在線程中獲取tid(線程當前存在)
tid是主控線程的變量在用戶棧, 子線程看不到, 因此是主控線程獲取輸出的 輸出時可能值一致(但可能此線程已經被釋放,回收)
若是任意一個線程調用了exit或_exit,則整個進程的全部線程都終止,因爲從main函數return也至關於調用exit,爲了防止新建立的線程尚未獲得執行就終止,咱們在main函數return以前延時1秒,這只是一種權宜之計。
pthread_exit
線程退出函數
調用線程退出函數,注意和exit函數的區別,任何線程裏exit致使進程退出,其餘線程未工做結束,主控線程退出時不能return或exit。
須要注意,pthread_exit或者return返回的指針所指向的內存單元必須是全局的或者是用malloc分配的,不能在線程函數的棧上分配,由於當其它線程獲得這個返回指針時線程函數已經退出了。
#include <pthread.h>
void pthread_exit(void *retval);
void *retval:線程退出時傳遞出的參數,能夠是退出值或地址,如是地址時,不能是線程內部申請的局部地址。
pthread_join
等待線程退出函數
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
pthread_t thread:回收線程的tid
void **retval:接收退出線程傳遞出的返回值
返回值:成功返回0,失敗返回錯誤號
調用該函數的線程將掛起等待,直到id爲thread的線程終止。thread線程以不一樣的方法終止,經過pthread_join獲得的終止狀態是不一樣的,總結以下:
若是thread線程經過return返回,retval所指向的單元裏存放的是thread線程函數的返回值。
若是thread線程被別的線程調用pthread_cancel異常終止掉,retval所指向的單元裏存放的是常數PTHREAD_CANCELED。(即爲-1)
若是thread線程是本身調用pthread_exit終止的,retval所指向的單元存放的是傳給pthread_exit的參數。
若是對thread線程的終止狀態不感興趣,能夠傳NULL給retval參數。
pthread_cancel
在進程內某個線程能夠取消另外一個線程。
#include <pthread.h>
int pthread_cancel(pthread_t thread);
被取消的線程,退出值,定義在Linux的pthread庫中常數PTHREAD_CANCELED的值是-1。能夠在頭文件pthread.h中找到它的定義:
#define PTHREAD_CANCELED ((void *) -1)
實例:
#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> void *thr_fn1(void *arg) { printf("thread 1 returning\n"); return (void *)1; } void *thr_fn2(void *arg) { printf("thread 2 exiting\n"); pthread_exit((void *)2); } void *thr_fn3(void *arg) { while(1) { printf("thread 3 writing\n"); sleep(1); } } int main(void) { pthread_t tid; void *tret; pthread_create(&tid, NULL, thr_fn1, NULL); pthread_join(tid, &tret); printf("thread 1 exit code %d\n", (int)tret); pthread_create(&tid, NULL, thr_fn2, NULL); pthread_join(tid, &tret); printf("thread 2 exit code %d\n", (int)tret); pthread_create(&tid, NULL, thr_fn3, NULL); sleep(3); pthread_cancel(tid); pthread_join(tid, &tret); printf("thread 3 exit code %d\n", (int)tret); return 0; }
結果:退出碼分別是1,2,-1.
對於線程3:若是線程中只有while(1),那麼pthread_cancle則不能終止線程。若是加了sleep(1);則能夠終止線程。
總結:signal什麼時候終止信號?(中斷,異常,系統調用)
cancle什麼時候事件什麼時候處理?(系統調用)
就是說線程沒有系統調用則不能使用cancle結束,因此咱們能夠用pthread_testcancle()來產生一次空調用,該函數的做用就是,產生一次系統調用檢測終止事件。
線程終止方式
若是須要只終止某個線程而不終止整個進程,能夠有三種方法:
1.從線程主函數return。這種方法對主控線程不適用,從main函數return至關於調用exit。
2.一個線程能夠調用pthread_cancel終止同一進程中的另外一個線程。
3.線程能夠調用pthread_exit終止本身。
同一進程的線程間,pthread_cancel向另外一線程發終止信號。系統並不會立刻關閉被取消線程,只有在被取消線程下次系統調用時,纔會真正結束線程。或調用pthread_testcancel,讓內核去檢測是否須要取消當前線程.
pthread_detach
將線程置爲分離態
#include <pthread.h>
int pthread_detach(pthread_t tid);
pthread_t tid:分離線程tid
返回值:成功返回0,失敗返回錯誤號。
通常狀況下,線程終止後,其終止狀態一直保留到其它線程調用pthread_join獲取它的狀態爲止。可是線程也能夠被置爲detach狀態,這樣的線程一旦終止就馬上回收它佔用的全部資源,而不保留終止狀態。不能對一個已經處於detach狀態的線程調用pthread_join,這樣的調用將返回EINVAL。若是已經對一個線程調用了pthread_detach就不能再調用pthread_join了。同理,若是對一個已經處於join回收狀態的線程調用depatch設置分離,也會失敗。
線程屬性
線程屬性初始化
先初始化線程屬性,再pthread_create建立線程
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr); //初始化線程屬性
int pthread_attr_destroy(pthread_attr_t *attr); //銷燬線程屬性所佔用的資源
線程分離狀態的函數:
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate); //設置線程屬性,分離or非分離
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate); //獲取程屬性,分離or非分離
pthread_attr_t *attr:被已初始化的線程屬性
int *detachstate:可選爲PTHREAD_CREATE_DETACHED(分離線程)和PTHREAD _CREATE_JOINABLE(非分離線程)這裏要注意的一點是,若是設置一個線程爲分離線程,而這個線程運行又很是快,它極可能在pthread_create函數返回以前就終止了,它終止之後就可能將線程號和系統資源移交給其餘的線程使用,這樣調用pthread_create的線程就獲得了錯誤的線程號。
要避免這種狀況能夠採起必定的同步措施,最簡單的方法之一是能夠在被建立的線程裏調用pthread_cond_timedwait函數,讓這個線程等待一下子,留出足夠的時間讓函數pthread_create返回。設置一段等待時間,是在多線程編程裏經常使用的方法。可是注意不要使用諸如wait()之類的函數,它們是使整個進程睡眠,並不能解決線程同步的問題。
NPTL
1.察看當前pthread庫版本
getconf GNU_LIBPTHREAD_VERSION
2.NPTL實現機制(POSIX),Native POSIX Thread Library
3.使用線程庫時gcc指定-lpthread
細節注意1.主線程退出其餘線程不退出,主線程應調用ptrhed_exit2.避免僵線程pthread_joinpthread_deatchpthread_create指定分離屬性 被join線程 可能在join函數返回前就釋放完本身的全部內存資源,因此不該當返回被回收線程棧中的值;3.malloc和mmap申請的內存能夠被其餘線程釋放4.若是線程終止時沒有釋放加鎖的互斥量,則該互斥量不能再被使用5.應避免在多線程模型中調用fork除非,立刻exec,子進程中只有調用fork的線程存在,其餘線程在子進程中均pthread_exit6.信號的複雜語義很難和多線程共存,應避免在多線程引入信號機制