在早期的LINUX內(nèi)核中,并不存在真正意義上的線程。當(dāng)時(shí)Linux中常用的線程pthread實(shí)際上是通過進(jìn)程來模擬的,也就是同過fork來創(chuàng)建“輕”進(jìn)程,并且這種輕進(jìn)程的線程也有個(gè)數(shù)的限制,最多只能有4096和此類線程同時(shí)運(yùn)行。2.4內(nèi)核消除了個(gè)數(shù)上的限制,并且允許在系統(tǒng)運(yùn)行中動(dòng)態(tài)的調(diào)整進(jìn)程數(shù)的上限,當(dāng)時(shí)采用的是Linux Thread 線程庫,它對(duì)應(yīng)的線程模型是“一對(duì)一”,而線程的管理是在內(nèi)核為的函數(shù)庫中實(shí)現(xiàn),這種線程得到了廣泛的應(yīng)用。但是它不與POSIX兼容。另外還有許多諸如信號(hào)處理,進(jìn)程ID等方面的問題沒有完全解決。
在的2.6內(nèi)核中,進(jìn)程調(diào)度通過重新的編寫,刪除了以前版本中的效率不高的算法,內(nèi)核框架頁也被重新編寫。
開始使用NPTL(Native POSIX Thread Library)線程庫,這個(gè)線程庫有以下幾個(gè)目標(biāo): - POSIX兼容 - 低啟動(dòng)開銷 - 低鏈接開銷 - 與Linux Thread應(yīng)用的二進(jìn)制兼容,軟硬件的可擴(kuò)展能力,與C++集成等。
這一切使得2.6的內(nèi)核多線程機(jī)制更加完備。從內(nèi)核2.6內(nèi)核開始linux開啟進(jìn)入多線程時(shí)代
參數(shù) - pthread_t *restrict tidp:創(chuàng)建的的線程ID號(hào) - const pthread_attr_t *restrict attr:指定線程的Attributes,若使用默認(rèn)值可以設(shè)置為NULL - void (*start_rtn)(void ):線程運(yùn)行時(shí)的任務(wù)(函數(shù))指針 - void *restrict arg:運(yùn)行start_rtn指針指向的函數(shù)時(shí),傳入的參數(shù)
pthread_create出錯(cuò)的時(shí)候不會(huì)設(shè)置errno,而是直接通過返回值返回錯(cuò)誤代碼
pthread_self可以獲取線程id號(hào),而通過getpid獲取的是當(dāng)前進(jìn)程的pid。
pthread_attr_init屬性對(duì)象主要包括是否綁定、是否分離、堆棧大小、優(yōu)先級(jí)。默認(rèn)的屬性為非綁定、非分離、缺省的堆棧、與父進(jìn)程同樣級(jí)別的優(yōu)先級(jí)。 - 綁定:關(guān)于線程的綁定,牽涉到另外一個(gè)概念:輕進(jìn)程(LWP:Light Weight PRocess)。輕進(jìn)程可以理解為內(nèi)核線程,它位于用戶層和系統(tǒng)層之間。系統(tǒng)對(duì)線程資源的分配、對(duì)線程的控制是通過輕進(jìn)程來實(shí)現(xiàn)的,一個(gè)輕進(jìn)程可以控制一個(gè)或多個(gè)線程。 默認(rèn)狀況下,啟動(dòng)多少輕進(jìn)程、哪些輕進(jìn)程來控制哪些線程是由系統(tǒng)來控制的,這種狀況即稱為非綁定的。綁定狀況下,則顧名思義,即某個(gè)線程固定的”綁”在一個(gè)輕進(jìn)程之上。被綁定的線程具有較高的響應(yīng)速度,這是因?yàn)镃PU時(shí)間片的調(diào)度是面向輕進(jìn)程的,綁定的線程可以保證在需要的時(shí)候它總有一個(gè)輕進(jìn)程可用。通過設(shè)置被綁定的輕進(jìn)程的優(yōu)先級(jí)和調(diào)度級(jí)可以使得綁定的線程滿足諸如實(shí)時(shí)反應(yīng)之類的要求。pthread_attr_setscope可以設(shè)定線程的綁定狀態(tài)
/*設(shè)置線程綁定狀態(tài)的函數(shù)為 pthread_attr_setscope,它有兩個(gè)參數(shù),第一個(gè)是指向?qū)傩越Y(jié)構(gòu)的指針,第二個(gè)是綁定類型,它有兩個(gè)取值: PTHREAD_SCOPE_SYSTEM(綁定的):表示與系統(tǒng)中所有線程一起競(jìng)爭(zhēng)CPU時(shí)間 ,PTHREAD_SCOPE_PROCESS(非綁定的):表示僅與同進(jìn)程中的線程競(jìng)爭(zhēng)CPU*/pthread_attr_t attr;pthread_t tid;/*初始化屬性值,均設(shè)為默認(rèn)值*/pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);pthread_create(&tid, &attr, (void *) my_function, NULL);//獲取當(dāng)前的模式int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope);分離模式設(shè)置:線程分為分離模式和非分離模式,顧名思義在分離模式下,當(dāng)線程退出時(shí),所有的資源都會(huì)自動(dòng)釋放。非分離的線程A終止時(shí),其線程ID和退出狀態(tài)將保留,直到另外一個(gè)線程調(diào)用 pthread_join(A)。設(shè)置線程分離狀態(tài)的函數(shù)為 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)第二個(gè)參數(shù)可選為PTHREAD_CREATE_DETACHED(分離線程)和 PTHREAD _CREATE_JOINABLE(非分離線程)pthread_attr_t attr;pthread_t tid;/*初始化屬性值,均設(shè)為默認(rèn)值*/pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);pthread_create(&tid, &attr, (void *) my_function, NULL);//也可以直接調(diào)用pthread_detach完成分離模式的設(shè)置int pthread_detach(pthread_t tid);//獲取當(dāng)前的模式int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)/*值得注意的是:如果設(shè)置一個(gè)線程為分離線程,而這個(gè)線程運(yùn)行又非常快,它很可能在pthread_create函數(shù)返回之前就終止了,它終止以后就可能將線程號(hào)和系統(tǒng)資源移交給其他的線程使用,這樣調(diào)用pthread_create的線程就得到了錯(cuò)誤的線程號(hào)。要避免這種情況可以采取一定的同步措施,最簡(jiǎn)單的方法之一是可以在被創(chuàng)建的線程里調(diào)用pthread_cond_timewait函數(shù),讓這個(gè)線程等待一會(huì)兒,留出足夠的時(shí)間讓函數(shù)pthread_create返回。設(shè)置一段等待時(shí)間,是在多線程編程里常用的方法。*/堆棧設(shè)置:默認(rèn)棧的大小為8M,若直接在棧上分配一個(gè)較大的緩存char p[1024*1024*8];毫無疑問一定會(huì)提示段錯(cuò)誤。可以通過pthread_attr_setstacksize設(shè)置棧的大小。pthread_attr_t attr; int size;//獲取當(dāng)前棧的大小pthread_attr_init(&attr); pthread_attr_getstacksize(&attr, &size); //設(shè)置棧的大小pthread_attr_setstacksize(&attr, size)調(diào)度策略:通過pthread_attr_getschedpolicy和pthread_attr_setschedpolicy獲取和設(shè)置調(diào)度策略。調(diào)度策略可能的值是先進(jìn)先出(SCHED_FIFO)、輪轉(zhuǎn)法(SCHED_RR),或其它(SCHED_OTHER)。int pthread_attr_getschedpolicy(const pthread_attr_t*attr,int *policy);int pthread_attr_setschedpolicy(pthread_attr_t *attr,intpolicy);優(yōu)先級(jí):通過pthread_attr_getschedparam 和pthread_attr_setschedparam分別用來設(shè)置和得到線程的調(diào)度參數(shù)(優(yōu)先級(jí))//函數(shù)原型int pthread_attr_getschedparam(const pthread_attr_t*attr,struct sched_param *param);int pthread_attr_setschedparam(pthread_attr_t *attr,conststruct sched_param *param);struct sched_param{ intsched_priority;};#include <pthread.h>#include <sched.h>pthread_attr_t attr; pthread_t tid;sched_param param;int newprio=20; /*初始化屬性*/pthread_attr_init(&attr); /*設(shè)置優(yōu)先級(jí)*/pthread_attr_getschedparam(&attr, ¶m); param.sched_priority=newprio;pthread_attr_setschedparam(&attr, ¶m);pthread_create(&tid, &attr, (void *)myfunction, myarg);銷毀pthread_attr_t int pthread_attr_destroy(pthread_attr_t*attr);要記得用完后一定要destroy.POSIX 標(biāo)準(zhǔn)要求: When a thread attributes object is no longer required, it should be destroyed using the pthread_attr_destroy() function. Destroying a thread attributes object has no effect on threads that were created using that object.若線程A調(diào)用pthread_join(B, &rval_ptr)后被阻塞,直到B退出。若A需要直到B 的退出代碼,則需要調(diào)用phtread_exit(rval_ptr)退出,但rval_ptr指向的內(nèi)存的生命周期,不應(yīng)該指向B的Stack中的數(shù)據(jù)。
pthread_cleanup_push 與pthread_cleanup_pop通常配合pthread_cancel使用,完成后續(xù)的清理工作!
#include <stdlib.h> #include <stdio.h> #include <errno.h> #include <pthread.h> #include <unistd.h>static void pthread_func_1 (void *); static void pthread_func_2 (void *); static void * pthread_func_3(void * );static void clean_fun1(void * );static void clean_fun2(void * );/*線程1:pthread_func_1 游離模式,主動(dòng)調(diào)用pthread_exit退出線程2:pthread_func_2 非游離模式,通過return退出。線程3:pthread_func_3 非游離模式,主線程調(diào)用pthread_cancel 使其退出,配合pthread_cleanup_push 與pthread_cleanup_pop 做后續(xù)的清理工作!*/int main (int argc, char** argv) { pthread_t pt_1 = 0; pthread_t pt_2 = 0; pthread_t pt_3 = 0; pthread_attr_t atrr = {0}; int ret = 0; printf("threat test!/n"); /*初始化屬性線程屬性*/ pthread_attr_init (&atrr); pthread_attr_setscope (&atrr, PTHREAD_SCOPE_SYSTEM); pthread_attr_setdetachstate (&atrr, PTHREAD_CREATE_DETACHED); ret = pthread_create (&pt_1, &atrr, pthread_func_1, NULL); if (ret != 0) { perror ("pthread_1_create"); } ret = pthread_create (&pt_2, NULL, pthread_func_2, NULL); if (ret != 0) { perror ("pthread_2_create"); } ret = pthread_create (&pt_3, NULL, pthread_func_3, NULL); if (ret != 0) { perror ("pthread_3_create"); } printf("waiting for pthread_2 exiting!/n"); pthread_join (pt_2, NULL); printf("pthread_2 has exited!/n"); printf("begin to cancel pthread_3!/n"); sleep(2); ret=pthread_cancel(pt_3); if(ret!=0) { perror("cancel error:"); exit(0); } printf("waiting for pthread_3 exiting!/n"); pthread_join (pt_3, NULL); printf("pthread_3 has exited!/n"); return 0; } static void pthread_func_1 (void * para) { int i = 0; for (; i < 6; i++) { printf ("This is pthread_1./n"); if (i == 2) { pthread_exit (0); } } return; } static void pthread_func_2 (void * para) { int i = 0; for (; i < 4; i ++) { sleep(1); printf ("This is pthread_2./n"); } printf ("pthread_2 will be exit!/n"); return; } static void * pthread_func_3(void * arg){ int i=0; pthread_cleanup_push(clean_fun1,NULL); pthread_cleanup_push(clean_fun2,NULL); for(i=0 ; i<100 ; i++) { sleep(1); printf ("This is pthread_3./n"); } //這里要注意,如果將sleep(100);換成while(1);的話,程序會(huì)一直暫停.push和pop要成對(duì)出現(xiàn). //因?yàn)閣hile(1);運(yùn)行的太快,線程不接受cancel信號(hào) //while(1); pthread_cleanup_pop(0); pthread_cleanup_pop(0); return NULL;}static void clean_fun1(void * arg){ printf("this is clean fun1/n");}static void clean_fun2(void * arg){ printf("this is clean fun2/n");}gcc -g -pthread threadTest.c -lpthread -o test 生成測(cè)試代碼
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注