12.6 線程的屬性:
線程建立後,在程序退出以前咱們能夠經過pthread_join再次與線程同步,在結束的時候向主線程返回一些數據。有時候咱們不須要線程結束的時候向主線程返回數據,也不須要主線程等待他的結束,這一類型的線程叫作脫離線程。能夠經過修改線程的屬性或者pthread_deatch的方法來建立它們。
線程屬性最重要的函數就是pthread_attr_init,它的做用是初始化一個線程屬性對象。
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
與前面同樣,該函數成功時返回0,失敗時返回錯誤代碼。
還有一個回收函數pthread_attr_destory,它的目的是對屬性對象進行清理和回收,一旦對象回收 了,除非從新被初始化,否者不能再使用。
初始化一個線程對象後,咱們就能夠調用其餘的函數來設置不一樣的屬性行爲。主要的函數以下:多線程
1 #include<pthread.h> 2 int pthread_attr_setdetachstate(pthread_attr_t* attr,int detachstate); 3 int pthread_attr_getdetachstate(const pthread_attr_t* attr,int detachstate); 4 int pthread_attr_setschedpolicy(pthread_attr_t*attr,int policy); 5 int pthread_attr_getschegpolicy(const pthread_attr_t* attr,int policy); 6 int pthread_attr_setschedparam(pthread_attr_t* attr,struct sched_param* param); 7 int pthread_attr_getschedparam(const pthread_attr_t* attr,struct sched_param* param); 8 int pthread_attr_setinheritsched(pthead_attr_t* attr, int inherit); 9 int pthread_attr_getinheritsched(const pthread_attr_t* attr,int* inhert); 10 int pthread_attr_setscope(pthread_attr_t* attr,int scope); 11 int pthread_attr_getscope(const pthread_attr_t* attr ,int * scope); 12 int pthread_attr_setstacksize(pthread_attr_t* attr,int scope); 13 int pthread_attr_getstacksize(const pthread_attr_t* attr,int* scope);
可見線程可使用的屬性不少,可是一般不須要設置太多的屬性就能夠正常工做。
❑ detachedstate:這個屬性容許咱們無需對線程進行從新合併。與大多數_set類函數同樣,它以一個屬性指針和一個標誌爲參數來肯定須要的狀態。pthread_attr_setdetachstate函數可能用到的兩個標誌分別是PTHREAD_CREATE_JOINABLE和PTHREAD_CREATE_DETACHED。這個屬性的默認標誌值是PTHREAD_CREATE_JOINABLE,因此能夠容許兩個線程從新合併。若是標誌設置爲PTHREAD_CREATE_DETACHED,就不能調用pthread_join來得到另外一個線程的退出狀態。
❑ schedpolicy:這個屬性控制線程的調度方式。它的取值能夠是SCHED_OTHER、SCHED_RP和SCHED_FIFO。這個屬性的默認值爲SCHED_OTHER。另外兩種調度方式只能用於以超級用戶權限運行的進程,由於它們都具有實時調度的功能,但在行爲上略有區別。SCHED_RP使用循環(round-robin)調度機制,而SCHED_FIFO使用「先進先出」策略。
❑ schedparam:這個屬性是和schedpolicy屬性結合使用的,它能夠對以SCHED_OTHER策略運行的線程的調度進行控制。
❑ inheritsched:這個屬性可取兩個值:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED。它的默認取值是PTHREAD_EXPLICIT_SCHED,表示調度由屬性明確地設置。若是把它設置爲PTHREAD_INHERIT_SCHED,新線程將沿用其建立者所使用的參數。
❑ scope:這個屬性控制一個線程調度的計算方式。
❑ stacksize:這個屬性控制線程建立的棧大小,單位爲字節。它屬於POSIX規範中的「可選」部分,只有在定義了宏_POSIX_THREAD_ATTR_STACKSIZE的實現版本中才支持。Linux在實現線程時,默認使用的棧很大,因此這個功能對Linux來講顯得有些多餘。
實驗:脫離線程
//建立脫離線程,函數
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void* thread_function(void* arg); char message[]={"Hello thread!"}; int thread_finished=0; int main() { pthread_t a_thread; int res; pthread_attr_t pattr; //初始化屬性 res=pthread_attr_init(&pattr); if(res!=0) { perror("Init threadattr failed"); exit(EXIT_FAILURE); } //設置屬性 res=pthread_attr_setdetachstate(&pattr,PTHREAD_CREATE_DETACHED); if(res!=0) { perror("Setting attr failed"); exit(EXIT_FAILURE); } //建立線程 res=pthread_create(&a_thread,&pattr,thread_function,(void*)message); if(res!=0) { perror("Create thread failed"); exit(EXIT_FAILURE); } //屬性使用完畢後釋放資源 (void)pthread_attr_destroy(&pattr); //循環,等待新線程設置結束標準;這裏代表主線程和其餘線程共享全局變量。 while(thread_finished!=1) { printf("Wating for thread finished\n"); sleep(1); } printf("other thread finished\n"); exit(EXIT_SUCCESS); return 0; } void* thread_function(void*arg) { printf("Thread is running.\nArgument is :%s\n",(char*)arg); sleep(1); printf("Second thread setting finished flag,and exiting now\n"); thread_finished=1; pthread_exit(NULL); }
線程屬性:調度
另一個可能須要修改的屬性:調度。改變調度屬性和設置脫離狀態很是相似,可使用sched_get_priority_max和sched_get_priority_min這兩個屬性來差早可用的優先級別。
實驗:調度ui
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> void* thread_function(void* arg); char message[]={"Hello thread!"}; int thread_finished=0; int main() { int max_policy; int min_policy; struct sched_param sched_value; pthread_t a_thread; int res; pthread_attr_t pattr; //初始化屬性 res=pthread_attr_init(&pattr); if(res!=0) { perror("Init threadattr failed"); exit(EXIT_FAILURE); } //設置脫離屬性 res=pthread_attr_setdetachstate(&pattr,PTHREAD_CREATE_DETACHED); if(res!=0) { perror("Setting attr failed"); exit(EXIT_FAILURE); } //設置調度策略 res=pthread_attr_setschedpolicy(&pattr,SCHED_OTHER); if(res!=0) { perror("Set sched failed"); exit(EXIT_FAILURE); } //查找可以使用的優先級 max_policy=sched_get_priority_max(SCHED_OTHER); min_policy=sched_get_priority_min(SCHED_OTHER); //設置優先級 sched_value.sched_priority=min_policy; res=pthread_attr_setschedparam(&pattr,&sched_value); if(res!=0) { perror("Set sched attr failed"); exit(EXIT_FAILURE); } //建立線程 res=pthread_create(&a_thread,&pattr,thread_function,(void*)message); if(res!=0) { perror("Create thread failed"); exit(EXIT_FAILURE); } (void)pthread_attr_destroy(&pattr); //循環,等待新線程設置結束標準;這裏代表主線程和其餘線程共享全局變量。 while(thread_finished!=1) { printf("Wating for thread finished\n"); sleep(1); } printf("other thread finished\n"); exit(EXIT_SUCCESS); return 0; } void* thread_function(void*arg) { printf("Thread is running.\nArgument is :%s\n",(char*)arg); sleep(4); printf("Second thread setting finished flag,and exiting now\n"); thread_finished=1; pthread_exit(NULL); }
七、取消一個線程:
請求終止的函數:
int pthread_cancle(pthread_t thread);提供一個進程標識符,就能夠終止它,在主線程是如此簡單,可是在被取消的線程是就不是這麼簡單了!!
線程可使用pthread_setcanclestate設置本身的取消狀態:
int pthread_setcanclestate(int state,int*oldstate);
第一個參數能夠是PTHREAD_CANCLE_ENABLE這個值容許取消請求,PTHREAD_CANCLE_DISABLE,它的做用是忽略取消請求。oldstate指針用於獲取先前的狀態,沒有必要的時候能夠設置爲NULL; 若是取消請求被接受了,線程就能夠進入第二個控制層次,用pthread_setcanceltype設置取消類型。
int pthread_setcancletype(int type,int* oldtype);
type參數能夠有兩種取值:一個是PTHREAD_CANCEL_ASYNCHRONOUS(當即取消),它將使得在接收到取消請求後當即採起行動;另外一個是PTHREAD_CANCEL_DEFERRED(延遲取消),它將使得在接收到取消請求後,一直等待直到線程執行了下述函數之一後才採起行動。具體是函數pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。
實驗:取消一個線程spa
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> char message[]={"Hello thread!"}; void* thread_function(void*arg) { int i,res; res=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//在新建立的線程中,咱們首先將取消狀態設置爲容許取消, if(res!=0) { perror("set cacle state failed"); exit(EXIT_FAILURE); } res=pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);//而後將取消類型設置爲延遲取消 //res=pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL); if(res!=0) { perror("set cancle type error"); exit(EXIT_FAILURE); } printf("Thread_Function is runing\n"); //最後,線程在循環中等待被取消 for(i=0;i<10;i++) { printf("Thread is still runing\n"); sleep(1); } pthread_exit(NULL); } int main() { pthread_t a_thread; int res; void* thread_res; int i; //建立線程 //以一般的方法建立了新線程後,主線程休眠一下子(好讓新線程有時間開始執行),而後發送一個取消請求。 res=pthread_create(&a_thread,NULL,thread_function,NULL); if(res!=0) { perror("Create thread error"); exit(EXIT_FAILURE); } sleep(3); printf("Canceling thread \n"); res=pthread_cancel(a_thread); if(res!=0) { perror("cancel a thread failed"); exit(EXIT_FAILURE); } printf("wating for thread to finish\n"); if(res!=0) { perror("thread join failed"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
多線程:線程
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> void* thread_function(void* arg) { int my_number; int Rand; // my_number=(int)arg; my_number=*(int*)arg; printf("Thread_function runing from %d\n",my_number); Rand=1+(int)(9.0*rand()/(RAND_MAX+1.0)); sleep(Rand);//休眠一個隨機時間 printf("Bye from %d\n",my_number); pthread_exit(NULL); } int main() { int res; pthread_t thread_id[6]; void * thread_res; int num_of_thread; for(num_of_thread=0;num_of_thread<6;num_of_thread++) { //res=pthread_create(&thread_id[num_of_thread],NULL,thread_function,(void*)num_of_thread); res=pthread_create(&thread_id[num_of_thread],NULL,thread_function,(void*)&num_of_thread); if(res==0) { sleep(1); } else { perror("Create thread fauiled"); exit(EXIT_FAILURE); } } for(num_of_thread=5;num_of_thread>=0;num_of_thread--) { res=pthread_join(thread_id[num_of_thread],&thread_res); if(res==0) { printf("Picked ip a thread \n"); } else { perror("Picedf up failed"); exit(EXIT_FAILURE); } } printf("Picede upo all\n"); printf("Done\n"); exit(EXIT_SUCCESS); }
咱們建立了許多線程並讓它們以隨意的順序結束執行。這個程序有一個小漏洞,若是將sleep調用從啓動線程的循環中刪除,它就會變得很明顯。
改進:指針
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <pthread.h> 6 7 void* thread_function(void* arg) 8 { 9 int my_number; 10 int Rand; 11 my_number=(int)arg; 12 printf("Thread_function runing from %d\n",my_number); 13 Rand=1+(int)(9.0*rand()/(RAND_MAX+1.0)); 14 15 sleep(Rand);//休眠一個隨機時間 16 printf("Bye from %d\n",my_number); 17 pthread_exit(NULL); 18 } 19 int main() 20 { 21 int res; 22 pthread_t thread_id[6]; 23 void * thread_res; 24 int num_of_thread; 25 for(num_of_thread=0;num_of_thread<6;num_of_thread++) 26 { 27 res=pthread_create(&thread_id[num_of_thread],NULL,thread_function,(void*)num_of_thread); 28 if(res!=0) 29 { 30 perror("Create thread fauiled"); 31 exit(EXIT_FAILURE); 32 } 33 } 34 for(num_of_thread=5;num_of_thread>=0;num_of_thread--) 35 { 36 res=pthread_join(thread_id[num_of_thread],&thread_res); 37 if(res==0) 38 { 39 printf("Picked ip a thread \n"); 40 } 41 else 42 { 43 perror("Picedf up failed"); 44 exit(EXIT_FAILURE); 45 } 46 } 47 printf("Picede upo all\n"); 48 printf("Done\n"); 49 exit(EXIT_SUCCESS); 50 }