POSIX線程庫API(全)(上)

線程庫

下面簡要論述了特定任務及其相關手冊頁。mysql

建立缺省線程

若是未指定屬性對象,則該對象爲 NULL,系統會建立具備如下屬性的缺省線程:程序員

  • 進程範圍sql

  • 非分離數據庫

  • 缺省棧和缺省棧大小安全

  • 零優先級多線程

還能夠用 pthread_attr_init() 建立缺省屬性對象,而後使用該屬性對象來建立缺省線程。有關詳細信息,請參見初始化屬性一節。函數

pthread_create 語法

使用 pthread_create(3C) 能夠向當前進程中添加新的受控線程。fetch

int pthread_create(pthread_t *tid, const pthread_attr_t *tattr,

    void*(*start_routine)(void *), void *arg);
#include <pthread.h>



pthread_attr_t() tattr;

pthread_t tid;

extern void *start_routine(void *arg);

void *arg;

int ret; 



/* default behavior*/

ret = pthread_create(&tid, NULL, start_routine, arg);



/* initialized with default attributes */

ret = pthread_attr_init(&tattr);

/* default behavior specified*/

ret = pthread_create(&tid, &tattr, start_routine, arg);

使用具備必要狀態行爲的 attr 調用 pthread_create() 函數。 start_routine 是新線程最早執行的函數。當 start_routine 返回時,該線程將退出,其退出狀態設置爲由 start_routine 返回的值。請參見pthread_create 語法。spa

pthread_create() 成功時,所建立線程的 ID 被存儲在由 tid 指向的位置中。.net

使用 NULL 屬性參數或缺省屬性調用 pthread_create() 時,pthread_create() 會建立一個缺省線程。在對 tattr 進行初始化以後,該線程將得到缺省行爲。

pthread_create 返回值

pthread_create() 在調用成功完成以後返回零。其餘任何返回值都表示出現了錯誤。若是檢測到如下任一狀況,pthread_create() 將失敗並返回相應的值。

EAGAIN

描述:

超出了系統限制,如建立的線程太多。

EINVAL

描述:

tattr 的值無效。

等待線程終止

pthread_join() 函數會一直阻塞調用線程,直到指定的線程終止。

pthread_join 語法

使用 pthread_join(3C) 等待線程終止。

int pthread_join(thread_t tid, void **status);
#include <pthread.h>



pthread_t tid;

int ret;

void *status;



/* waiting to join thread "tid" with status */

ret = pthread_join(tid, &status);



/* waiting to join thread "tid" without status */

ret = pthread_join(tid, NULL);

指定的線程必須位於當前的進程中,並且不得是分離線程。有關線程分離的信息,請參見設置分離狀態。

status 不是 NULL 時,status 指向某個位置,在 pthread_join() 成功返回時,將該位置設置爲已終止線程的退出狀態。

若是多個線程等待同一個線程終止,則全部等待線程將一直等到目標線程終止。而後,一個等待線程成功返回。其他的等待線程將失敗並返回 ESRCH 錯誤。

pthread_join() 返回以後,應用程序可回收與已終止線程關聯的任何數據存儲空間。

pthread_join 返回值

調用成功完成後,pthread_join() 將返回零。其餘任何返回值都表示出現了錯誤。若是檢測到如下任一狀況,pthread_join() 將失敗並返回相應的值。

ESRCH

描述:

沒有找到與給定的線程 ID 相對應的線程。

EDEADLK

描述:

將出現死鎖,如一個線程等待其自己,或者線程 A 和線程 B 互相等待。

EINVAL

描述:

與給定的線程 ID 相對應的線程是分離線程。

pthread_join() 僅適用於非分離的目標線程。若是沒有必要等待特定線程終止以後才進行其餘處理,則應當將該線程分離。

簡單線程的示例

在示例 2–1 中,一個線程執行位於頂部的過程,該過程首先建立一個輔助線程來執行 fetch() 過程。fetch() 執行復雜的數據庫查找操做,查找過程須要花費一些時間。

主線程將等待查找結果,但同時還執行其餘操做。所以,主線程將執行其餘活動,而後經過執行 pthread_join() 等待輔助線程。

將新線程的 pbe 參數做爲棧參數進行傳遞。這個線程參數之因此可以做爲棧參數傳遞,是由於主線程會等待輔助線程終止。不過,首選方法是使用 malloc 從堆分配存儲,而不是傳遞指向線程棧存儲的地址。若是將該參數做爲地址傳遞到線程棧存儲,則該地址可能無效或者在線程終止時會被從新分配。


示例 2–1 簡單線程程序

 

void mainline (...)

{

        struct phonebookentry *pbe;

        pthread_attr_t tattr;

        pthread_t helper;

        void *status;



        pthread_create(&helper, NULL, fetch, &pbe);



            /* do something else for a while */



        pthread_join(helper, &status);

        /* it's now safe to use result */

}



void *fetch(struct phonebookentry *arg)

{

        struct phonebookentry *npbe;

        /* fetch value from a database */



        npbe = search (prog_name)

            if (npbe != NULL)

                *arg = *npbe;

        pthread_exit(0);

}   



struct phonebookentry {

        char name[64];

        char phonenumber[32];

        char flags[16];

}

分離線程

pthread_detach(3C) 是 pthread_join(3C) 的替代函數,可回收建立時 detachstate 屬性設置爲 PTHREAD_CREATE_JOINABLE 的線程的存儲空間。

pthread_detach 語法

int pthread_detach(thread_t tid);
#include <pthread.h>



pthread_t tid;

int ret;



/* detach thread tid */

ret = pthread_detach(tid);

pthread_detach() 函數用於指示應用程序在線程 tid 終止時回收其存儲空間。若是 tid 還沒有終止,pthread_detach() 不會終止該線程。

pthread_detach 返回值

pthread_detach() 在調用成功完成以後返回零。其餘任何返回值都表示出現了錯誤。若是檢測到如下任一狀況,pthread_detach() 將失敗並返回相應的值。

EINVAL

描述:

tid 是分離線程。

ESRCH

描述:

tid 不是當前進程中有效的未分離的線程。

爲線程特定數據建立鍵

單線程 C 程序有兩類基本數據:局部數據和全局數據。對於多線程 C 程序,添加了第三類數據:線程特定數據。線程特定數據與全局數據很是類似,區別在於前者爲線程專有。

線程特定數據基於每線程進行維護。TSD(特定於線程的數據)是定義和引用線程專用數據的惟一方法。每一個線程特定數據項都與一個做用於進程內全部線程的鍵關聯。經過使用 key,線程能夠訪問基於每線程進行維護的指針 (void *)。

pthread_key_create 語法

int pthread_key_create(pthread_key_t *key,

    void (*destructor) (void *));
#include <pthread.h>



pthread_key_t key;

int ret;



/* key create without destructor */

ret = pthread_key_create(&key, NULL);



/* key create with destructor */

ret = pthread_key_create(&key, destructor);

可使用 pthread_key_create(3C) 分配用於標識進程中線程特定數據的鍵。鍵對進程中的全部線程來講是全局的。建立線程特定數據時,全部線程最初都具備與該鍵關聯的 NULL 值。

使用各個鍵以前,會針對其調用一次 pthread_key_create()。不存在對鍵(爲進程中全部的線程所共享)的隱含同步。

建立鍵以後,每一個線程都會將一個值綁定到該鍵。這些值特定於線程而且針對每一個線程單獨維護。若是建立該鍵時指定了 destructor 函數,則該線程終止時,系統會解除針對每線程的綁定。

pthread_key_create() 成功返回時,會將已分配的鍵存儲在 key 指向的位置中。調用方必須確保對該鍵的存儲和訪問進行正確的同步。

使用可選的析構函數 destructor 能夠釋放過期的存儲。若是某個鍵具備非 NULL destructor 函數,而線程具備一個與該鍵關聯的非 NULL 值,則該線程退出時,系統將使用當前的相關值調用 destructor 函數。destructor 函數的調用順序不肯定。

pthread_key_create 返回值

pthread_key_create() 在成功完成以後返回零。其餘任何返回值都表示出現了錯誤。若是出現如下任一狀況,pthread_key_create() 將失敗並返回相應的值。

EAGAIN

描述:

key 名稱空間已經用完。

ENOMEM

描述:

此進程中虛擬內存不足,沒法建立新鍵。

刪除線程特定數據鍵

使用 pthread_key_delete(3C) 能夠銷燬現有線程特定數據鍵。因爲鍵已經無效,所以將釋放與該鍵關聯的全部內存。引用無效鍵將返回錯誤。Solaris 線程中沒有相似的函數。

pthread_key_delete 語法

int pthread_key_delete(pthread_key_t key);
#include <pthread.h>



pthread_key_t key;

int ret;



/* key previously created */

ret = pthread_key_delete(key);

若是已刪除鍵,則使用調用 pthread_setspecific()pthread_getspecific() 引用該鍵時,生成的結果將是不肯定的。

程序員在調用刪除函數以前必須釋放全部線程特定資源。刪除函數不會調用任何析構函數。反覆調用 pthread_key_create()pthread_key_delete() 可能會產生問題。若是 pthread_key_delete() 將鍵標記爲無效,而以後 key 的值再也不被重用,那麼反覆調用它們就會出現問題。對於每一個所需的鍵,應當只調用 pthread_key_create() 一次。

pthread_key_delete 返回值

pthread_key_delete() 在成功完成以後返回零。其餘任何返回值都表示出現了錯誤。若是出現如下狀況,pthread_key_delete() 將失敗並返回相應的值。

EINVAL

描述:

key 的值無效。

設置線程特定數據

使用 pthread_setspecific(3C) 能夠爲指定線程特定數據鍵設置線程特定綁定。

pthread_setspecific 語法

int pthread_setspecific(pthread_key_t key, const void *value);
#include <pthread.h>



pthread_key_t key;

void *value;

int ret;



/* key previously created */

ret = pthread_setspecific(key, value);

pthread_setspecific 返回值

pthread_setspecific() 在成功完成以後返回零。其餘任何返回值都表示出現了錯誤。若是出現如下任一狀況,pthread_setspecific() 將失敗並返回相應的值。

ENOMEM

描述:

虛擬內存不足。

EINVAL

描述:

key 無效。


注 –

設置新綁定時,pthread_setspecific() 不會釋放其存儲空間。必須釋放現有綁定,不然會出現內存泄漏。


獲取線程特定數據

請使用 pthread_getspecific(3C) 獲取調用線程的綁定,並將該綁定存儲在 value 指向的位置中。

pthread_getspecific 語法

void *pthread_getspecific(pthread_key_t key);
#include <pthread.h>



pthread_key_t key;

void *value;



/* key previously created */

value = pthread_getspecific(key);

pthread_getspecific 返回值

pthread_getspecific 不返回任何錯誤。

全局和專用線程特定數據的示例

示例 2–2 顯示的代碼是從多線程程序中摘錄出來的。這段代碼能夠由任意數量的線程執行,但該代碼引用了兩個全局變量:errno 和 mywindow。這些全局值實際上應當是對每一個線程專用項的引用。


示例 2–2 線程特定數據-全局但專用

 

body() {

    ...



    while (write(fd, buffer, size) == -1) {

        if (errno != EINTR) {

            fprintf(mywindow, "%s\n", strerror(errno));

            exit(1);

        }

    }



    ...



}

errno 引用應該從線程所調用的例程獲取系統錯誤,而從其餘線程所調用的例程獲取系統錯誤。所以,線程不一樣,引用 errno 所指向的存儲位置也不一樣。

mywindow 變量指向一個 stdio (標準 IO)流,做爲線程專屬的流窗口。所以,與 errno 同樣,線程不一樣,引用 mywindow 所指向的存儲位置也不一樣。最終,這個引用指向不一樣的流窗口。惟一的區別在於系統負責處理 errno,而程序員必須處理對 mywindow 的引用。

下一個示例說明對 mywindow 的引用如何工做。預處理程序會將對 mywindow 的引用轉換爲對 _mywindow() 過程的調用。

此例程隨後調用 pthread_getspecific()pthread_getspecific() 接收 mywindow_key 全局變量做爲輸入參數,以輸出參數 win 返回該線程的窗口。


示例 2–3 將全局引用轉化爲專用引用

 

thread_key_t mywin_key;



FILE *_mywindow(void) {

    FILE *win;



    win = pthread_getspecific(mywin_key);

    return(win);

}



#define mywindow _mywindow()



void routine_uses_win( FILE *win) {

    ...

}



void thread_start(...) {

    ...

    make_mywin();

    ...

    routine_uses_win( mywindow )

    ...

}

mywin_key 變量標識一類變量,對於該類變量,每一個線程都有其各自的專用副本。這些變量是線程特定數據。每一個線程都調用 make_mywin() 以初始化其時限並安排其 mywindow 實例以引用線程特定數據。

調用此例程以後,此線程能夠安全地引用 mywindow,調用 _mywindow() 以後,此線程將得到對其專用時限的引用。引用 mywindow 相似於直接引用線程專用數據。

示例 2–4 說明如何設置引用。


示例 2–4 初始化線程特定數據

 

void make_mywindow(void) {

    FILE **win;

    static pthread_once_t mykeycreated = PTHREAD_ONCE_INIT;



    pthread_once(&mykeycreated, mykeycreate);



    win = malloc(sizeof(*win));

    create_window(win, ...);



    pthread_setspecific(mywindow_key, win);

}



void mykeycreate(void) {

    pthread_key_create(&mywindow_key, free_key);

}



void free_key(void *win) {

    free(win);

}

首先,獲得一個惟一的鍵值,mywin_key。此鍵用於標識線程特定數據類。第一個調用 make_mywin() 的線程最終會調用 pthread_key_create(),該函數將惟一的 key 賦給其第一個參數。第二個參數是 destructor 函數,用於在線程終止後將該線程的特定於該線程的數據項實例解除分配。

接下來爲調用方的線程特定數據項的實例分配存儲空間。獲取已分配的存儲空間,調用 create_window(),以便爲該線程設置時限。win 指向爲該時限分配的存儲空間。最後,調用 pthread_setspecific(),將 win 與該鍵關聯。

之後,每當線程調用 pthread_getspecific() 以傳遞全局 key,線程都會得到它在前一次調用 pthread_setspecific() 時設置的與該鍵關聯的值)。

線程終止時,會調用在 pthread_key_create() 中設置的 destructor 函數。每一個 destructor 函數僅在終止線程經過調用 pthread_setspecific() 爲 key 賦值以後纔會被調用。

相關文章
相關標籤/搜索