天天看點

Pthreads線程的基本常識

<b>1.Pthreads</b><b>中線程的接口函數</b>

<b></b>

與線程相關的頭檔案為pthread.h,編譯時要連接配接的庫為pthread。

pthread_t thread;

線程的資料類型為pthread_t。

int pthread_equal(pthread t1,pthread t2);

判斷兩個線程辨別符是不是代表的是同一個線程。線程辨別符隻有相等和不等的關系,沒有大小關系。

int pthread_create(pthread_t * thread,

               const pthread_attr_t * attr, void *(*start)(void *),void * arg);

pthread_create函數将建立一個線程,第一個傳出參數為系統配置設定給線程的辨別符。第二個參數為線程設定的屬性。第三個參數為線程開始運作後執行的啟動函數。第四個參數為函數要用到的參數。

pthread_t pthread_self(void);

pthread_self函數将獲得目前線程的辨別符。傳回值即為目前線程的辨別符。獲得線程辨別符的方法有兩種:(1)使用pthread_create函數.(2)使用pthread_self函數.

int sched_yield(void);

志願讓出處理器的使用權給其他線程使用。

int pthread_exit(void * value_ptr);

目前線程退出。

int pthread_detach(pthread_t thread);

當線程進入終止狀态時,清理線程所占資源後進入回收狀态。

int pthread_join(pthread_t thread,void ** value_ptr);

阻塞等待thread線程執行結束,并得到該線程的傳回值。注意第二個參數應該為指針的指針。該函數内部會負責調用pthread_detach保證線程的資源得到釋放。

<b> </b>

<b>2.</b><b>主線程和普通線程的差別</b>

(1)主線程使用return、exit、或者正常執行到主函數的結尾退出時,所有的線程都将退出。如果主線程需要其他線程執行結束後才退出,可以使用以下方式:1)調用pthread_join,這時調用的主線程将被阻塞,直到join的線程執行結束後,才接着往下執行。2)調用pthread_exit函數,但是pthread_exit函數傳回主線程後,系統不能正常得到程式的傳回狀态。3)使用條件變量等待其他線程執行結束。

(2)主線程的參數傳遞方式和普通線程不一樣,主線程通過main函數中的argc和argv得到各個參數,而普通線程需要将所有的參數封裝到一起,傳給線程的參數。

(3)一般主線程的棧的大小比普通現成的大很多。主線程使用的是程序的棧,是以會比較大。

(4)主線程的main函數是被外部的某個函數調用的,一般是連結的crt0.o這個檔案。ctr0(C running time)是一個啟動例程,負責完成程序的初始化工作後,調用main函數。普通線程直接調用start函數。

<b>3.</b><b>線程的資源回收</b>

         線程執行完畢之後應該是放其所占用的資源:包括虛拟記憶體,堆棧,鎖,信号量等資訊。一般線程調用了pthread_cancel,pthread_exit或者執行完其start函數中的邏輯或者執行完了return語句,線程的狀态将進入終止狀态。進入終止狀态的線程并沒有釋放它所占用的資源,一般有以下三種方式:

         (1)建立線程的時候在第二個參數中設定detach屬性。

         (2)使用pthread_detach函數

         (3)使用pthread_join函數

         線程所占用的資源有些被釋放,有些被回收利用。在啟動新的線程的時候可以減少一部分開銷。

         線程的分離(detach)同線程執行其邏輯沒有必然聯系。還有需要注意的是,一個線程隻能被join一次,如果有多個線程都需要等待一個線程,使用信号量實作。

         pthread_cancel結束的線程,其傳回值隻有一種:PTHREAD_CANCELLED

<b>4.</b><b>線程的傳回值</b>

<b>         </b>使用線程的傳回值最容易出現的錯誤就是使用了線程内部的棧中資料的位址作為傳回值。A線程建立了B線程,B線程可能會在A線程開始執行join之前,已經detach掉了。其棧早已失效,這時如果線程内部傳回的是棧中某資料的位址一定出錯。

         一般線程的傳回值可以使用以下三種方式:

         (1)使用全局變量

         (2)線程内部使用malloc開辟空間,回傳給需要的線程。該線程負責釋放這段記憶體

         (3)使用傳出參數,即調用線程使用malloc在堆上開辟空間,并負責資料的維護

<b>5.</b><b>代碼示例</b>

#include&lt;stdio.h&gt; 

#include&lt;pthread.h&gt; 

#include "../error.h" 

void * thread_routin(void * arg) 

        return arg; 

int main(int argc,char * argv[]) 

        pthread_t thread; 

        void * thread_result; 

        int status; 

        status = pthread_create(&amp;thread,NULL,thread_routin,NULL); 

        if(0 != status) 

                err_abort("create thread error.",status); 

        status = pthread_join(thread,&amp;thread_result); 

                err_abort("join thread error.",status); 

        if(NULL != thread_result) 

                fprintf(stderr,"%s","Return value error.\n"); 

        return 0; 

以上程式是一個簡單的參數傳入傳出的示例程式。 

#include&lt;stdlib.h&gt; 

        status = pthread_join(thread,NULL); 

        { 

                fprintf(stderr,"%s \"%s\":%d: %s\n","thread join error",__FILE__,__LINE__,strerror(status)); 

                abort(); 

        } 

以上程式是一個故意出錯的程式,在Linux中程式會直接崩潰,提示“段錯誤”。

#include&lt;time.h&gt; 

void * thread_routin(void *arg) 

        sleep(5); 

int main(int argc,char *argv[]) 

        pthread_t thread ; 

        int result; 

                err_abort("creating thread error.",status); 

        result = 1; 

        pthread_exit((void *)&amp;result); 

        //return 0; 

這是一個測試main線程調用pthread_exit能否傳回需要的值的測試程式。該程式表明:在main線程中使用pthread_exit雖然能保證其他線程執行完畢,但是在系統無法得知整個程式的最後執行狀态。

        //pthread_exit(arg); 

        void * result; 

        int set_result = -1; 

        status = pthread_create(&amp;thread,NULL,thread_routin,(void *)&amp;set_result); 

        status = pthread_join(thread,&amp;result); 

                err_abort("joining thread error.",status); 

        printf("exit value is %d\n",*((int *)result)); 

        pthread_exit((void*)&amp;set_result); 

該程式對普通線程和主線程分别調用pthread_exit以測試線程的傳回值。主線程的傳回值系統無法得到,普通線程的傳回值卻可以得到。

本文轉自hipercomer 51CTO部落格,原文連結:http://blog.51cto.com/hipercomer/909941

繼續閱讀