線程pthread_join和分離式線程

CALLBACK_POINT_FUN pC  = NULL;

void call_fun(CALLBACK_POINT_FUN fun)
{
 pC = fun;
//方法1 單線程都用這樣方法
 pthread_t sh1;
 int ret;
 ret = pthread_create(&sh1, NULL, (void *)callback_thread, NULL);
 if(ret)
  printf("create thread is fail\n");
  
 pthread_join(sh1, NULL); //重要
 //若不加入這句。callback_thread() 將不會執行,pthread_join使一個線程等待另一個線程結束。
 //則而這個線程運行又非常快,線程處理函數得不到執行
 //它很可能在pthread_create函數返回之前就終止了


/* 方法2 多線程創建分離式線程 注意如果設置一個線程爲分離線程,
 而這個線程運行又非常快,它很可能在pthread_create函數返回之前就終止了
int ret ;
 printf("call_fun\n");
 
 pthread_t sh;
 pthread_attr_t attrca; 
 pthread_attr_init (&attrca);//分離式線程
 pthread_attr_setdetachstate (&attrca, PTHREAD_CREATE_DETACHED);
 if(ret = pthread_create(&sh, NULL, (void *)callback_thread, NULL))
 {
  printf("create thread failed\n");
 }
   usleep(1000); //讓主線程休息一會,等到子線程完成


   */
}

void callback_thread()

{
 printf("the thread is run\n");
  
}

 

線程可以看作是輕量級的進程,所有的程序都有一個主線程(main thread),主線程是進程的控制流或執行線程。在多線程程序中,主線程可以創建一個或多個對等線程(peer thread),從這個時間點開始,這些線程就開始併發執行。主線程和對等線程的區別僅在於主線程總是進程中第一個運行的線程。線程有兩個優點:資源消耗量少和方便的通信機制。

一、線程創建

需要的頭文件:pthread.h

線程標識符:pthread_t

主要線程函數:

(1)創建線程

int pthread_create ( pthread_t *thread,// 指向線程標識符的指針

pthread_attr_t *attr, // 設置線程屬性

void *(*start_routine) (void *), //線程運行函數的起始地址

void *arg ); // 運行函數的參數

當創建線程成功時,函數返回0,若不爲0則說明創建線程失敗,常見的錯誤返回代碼爲EAGAINEINVAL。前者表示系統限制創建新的線程,例如線程數目過多了;後者表示第二個參數代表的線程屬性值非法。創建線程成功後,新創建的線程則運行參數三和參數四確定的函數,原來的線程則繼續運行下一行代碼。

(2)結束線程

void pthread_exit (void *retval) ; //函數的返回代碼

(3)等待一個線程的結束

int pthread_join (pthread_t th, //被等待的線程標識符

void **thread_return); //一個用戶定義的指針,它可以用來存儲被等待線程的返回值。

這個函數是一個線程阻塞的函數,調用它的函數將一直等待到被等待的線程結束爲止,當函數返回時,被等待線程的資源被收回。

(4)獲取一個線程的ID

pthread_t pthread_self(void); //獲取本線程的線程ID

使用形式:

void thread1(void)

{...}

void thread2(void)

{...}

...

int ret;

pthread_t pt_1;    

pthread_t pt_2;

ret = pthread_create(&pt_1, NULL, (void *)thread1, NULL);

if (ret != 0) {...} /*線程創建失敗*/

ret = pthread_create(&pt_2, NULL, (void *)thread2, NULL);

if (ret != 0) {...} /*線程創建失敗*/

/*等待線程12的結束*/

pthread_join (pt_1, NULL);    

pthread_join (pt_2, NULL);

二、線程屬性

需要的頭文件:pthread.h

線程屬性標識符:pthread_attr_t

屬性值不能直接設置,須使用相關函數進行操作,初始化的函數爲pthread_attr_init,這個函數必須在pthread_create函數之前調用。

線程屬性主要包括如下屬性:作用域scope;棧尺寸stack size;棧地址stack address;優先級priority;分離的狀態detached state;調度策略和參數scheduling policy and parameters)。默認的屬性爲非綁定、非分離、缺省1M的堆棧、與父進程同樣級別的優先級。

線程可以在兩種競爭域內競爭資源:進程域(process scope):與同一進程內的其他線程;系統域(system scope):與系統中的所有線程。作用域屬性描述特定線程將與哪些線程競爭資源。一個具有系統域的線程將與整個系統中所有具有系統域的線程按照優先級競爭處理器資源,進行調度。

關於線程的綁定,牽涉到另外一個概念:輕進程(LWPLight Weight Process)。輕進程可以理解爲內核線程,它位於用戶層和系統層之間。系統對線程資源的分配、對線程的控制是通過輕進程來實現的,一個輕進程可以控制一個或多個線程。默認狀況下,啓動多少輕進程、哪些輕進程來控制哪些線程是由系統來控制的,這種狀況即稱爲非綁定的。綁定狀況下,則顧名思義,即某個線程固定的""在一個輕進程之上。被綁定的線程具有較高的響應速度,這是因爲CPU時間片的調度是面向輕進程的,綁定的線程可以保證在需要的時候它總有一個輕進程可用。通過設置被綁定的輕進程的優先級和調度級可以使得綁定的線程滿足諸如實時反應之類的要求。

線程的分離狀態決定一個線程以什麼樣的方式來終止自己。線程的默認屬性是非分離狀態,這種情況下,原有的線程等待創建的線程結束。只有當pthread_join()函數返回時,創建的線程纔算終止,才能釋放自己佔用的系統資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。應該根據自己的需要,選擇適當的分離狀態。設置線程分離狀態的函數爲:

pthread_attr_setdetachstatepthread_attr_t *attr, int detachstate)。

第二個參數可選爲PTHREAD_CREATE_DETACHED(分離線程)和 PTHREAD _CREATE_JOINABLE(非分離線程)。

這裏要注意的一點是,如果設置一個線程爲分離線程,而這個線程運行又非常快,它很可能在pthread_create函數返回之前就終止了,它終止以後就可能將線程號和系統資源移交給其他的線程使用,這樣調用pthread_create的線程就得到了錯誤的線程號。要避免這種情況可以採取一定的同步措施,最簡單的方法之一是可以在被創建的線程裏調用pthread_cond_timewait函數,讓這個線程等待一會兒,留出足夠的時間讓函數pthread_create返回。設置一段等待時間,是在多線程編程裏常用的方法。但是注意不要使用諸如wait()之類的函數,它們是使整個進程睡眠,並不能解決線程同步的問題。

另外一個可能常用的屬性是線程的優先級,它存放在結構sched_param中。

常用的幾個函數:

(1) pthread_attr_init

功能:        對線程屬性變量的初始化。

函數原型:   int pthread_attr_init (pthread_attr_t* attr);

函數傳入值:attr:線程屬性。

函數返回值:成功:0,失敗:-1

(2) pthread_attr_setscope

功能:       設置線程綁定屬性。

函數原型:   int pthread_attr_setscope (pthread_attr_t* attr, int scope);

函數傳入值:attr:線程屬性。

            scopePTHREAD_SCOPE_SYSTEM(綁定)PTHREAD_SCOPE_PROCESS(非綁定)

函數返回值:同(1)

(3) pthread_attr_setdetachstate

功能:        設置線程分離屬性。

函數原型:    int pthread_attr_setdetachstate (pthread_attr_t* attr, int detachstate);

函數傳入值:attr:線程屬性。

            detachstatePTHREAD_CREATE_DETACHED(分離)PTHREAD_CREATE_JOINABLE(非分離)

函數返回值:同(1)

(4) pthread_attr_setschedpolicy

功能:       設置創建線程的調度策略。

函數原型: int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy)

函數傳入值:attr:線程屬性;

            policy:線程調度策略:SCHED_FIFOSCHED_RRSCHED_OTHER

函數返回值:同(1)

(5) pthread_attr_setschedparam

功能:       設置線程優先級。

函數原型:   int pthread_attr_setschedparam (pthread_attr_t* attr, struct sched_param* param);

函數傳入值: attr:線程屬性。

             param:線程優先級。

函數返回值:同(1)

(6) pthread_attr_destroy

功能:        對線程屬性變量的銷燬。

函數原型:   int pthread_attr_destroy (pthread_attr_t* attr);

函數傳入值:attr:線程屬性。

函數返回值:同(1)

(7)其他

int pthread_attr_setguardsize(pthread_attr_t* attr,size_t guardsize);//設置新創建線程棧的保護區大小。

int pthread_attr_setinheritsched(pthread_attr_t* attr, int inheritsched);//決定怎樣設置新創建線程的調度屬性。

int pthread_attr_setstack(pthread_attr_t* attr, void* stackader,size_t stacksize);//兩者共同決定了線程棧的基地址以及堆棧的最小尺寸(以字節爲單位)。

int pthread_attr_setstackaddr(pthread_attr_t* attr, void* stackader);//決定了新創建線程的棧的基地址。

int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize);//決定了新創建線程的棧的最小尺寸(以字節爲單位)。

例:創建優先級爲10的線程。

pthread_attr_t attr;

struct sched_param param;

pthread_attr_init(&attr);

pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); //綁定

pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); //分離

pthread_attr_setschedpolicy(&attr, SCHED_RR);

param.sched_priority = 10;

pthread_attr_setschedparam(&attr, &param);

pthread_create(xxx, &attr, xxx, xxx);

pthread_attr_destroy(&attr);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章