pthread_once 和 pthread_key

來源:互聯網
上載者:User

一次性初始化

    有時候我們需要對一些posix變數只進行一次初始化,如線程鍵(我下面會講到)。如果我們進行多次初始化程式就會出現錯誤。

    在傳統的順序編程中,一次性初始化經常通過使用布爾變數來管理。控制變數被靜態初始化為0,而任何依賴於初始化的代碼都能測試該變數。如果變數值仍然為0,則它能實行初始化,然後將變數置為1。以後檢查的代碼將跳過初始化。

    但是在多線程程式設計中,事情就變的複雜的多。如果多個線程並發地執行初始化序列代碼,可能有2個線程發現控制變數為0,並且都實行初始化,而該過程本該僅僅執行一次。

如果我們需要對一個posix變數靜態初始化,可使用的方法是用一個互斥量對該變數的初始話進行控制。但有時候我們需要對該變數進行動態初始化,pthread_once就會方便的多。 

函數原形:

pthread_once_t once_control=PTHREAD_ONCE_INIT;

int pthread_once(pthread_once_t *once_control,void(*init_routine)(void));

參數:

once_control         控制變數

init_routine         初始化函數

傳回值:

若成功返回0,若失敗返回錯誤編號。

 類型為pthread_once_t的變數是一個控制變數。控制變數必須使用PTHREAD_ONCE_INIT宏靜態地初始化。

pthread_once函數首先檢查控制變數,判斷是否已經完成初始化,如果完成就簡單地返回;否則,pthread_once調用初始化函數,並且記錄下初始化被完成。如果在一個線程初始時,另外的線程調用pthread_once,則調用線程等待,直到那個現成完成初始話返回。

下面就是該函數的程式例子: 

#include <pthread.h>

pthread_once_t once=PTHREAD_ONCE_INIT;

pthread_mutex_t mutex; 

void once_init_routine(void) 

{

    int status;

    status=pthread_mutex_init(&mutex,NULL);

    if(status==0)

    printf(“Init success!,My id is %u”,pthread_self());

}

void *child_thread(void *arg)

{

    printf(“I’m child ,My id is %u”,pthread_self());

    pthread_once(&once,once_init_routine);

}

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

{

    pthread_t child_thread_id;

    pthread_create(&child_thread_id,NULL,child_thread,NULL);

    printf(“I’m father,my id is %u”,pthread_self());

    pthread_once(&once_block,once_init_routine);

    pthread_join(child_thread_id,NULL);

}

線程的私人資料

    在進程內的所有線程共用相同的地址空間,任何聲明為靜態或外部的變數,或在進程堆聲明的變數,都可以被進程所有的線程讀寫。那怎樣才能使線程式擁有自己的私人資料呢。

posix提供了一種方法,建立線程鍵。

函數原形:

int pthread_key_create(pthread_key *key,void(*destructor)(void *));

參數:

key           私人資料鍵

destructor    清理函數

傳回值:

若成功返回0,若失敗返回錯誤編號

   第一個參數為指向一個索引值的指標,第二個參數指明了一個destructor函數(清理函數),如果這個參數不為空白,那麼當每個線程結束時,系統將調用這個函數來釋放綁定在這個鍵上的記憶體塊。這個函數常和函數pthread_once一起使用,為了讓這個鍵只被建立一次。函數pthread_once聲明一個初始化函數,第一次調用pthread_once時它執行這個函數,以後的調用將被它忽略。

下面是程式例子: 

#include <pthread.h>

pthread_key_t tsd_key;

pthread_once_t key_once=PTHREAD_ONCE_INIT;

void once_routine(void)

{

int status;

status=pthread_key_create(&tsd_key,NULL);

if(status=0)

    printf(“Key create success! My id is %u/n”,pthread_self());

}

void *child_thread(void *arg)

{

printf(“I’m child,My id is %u/n”,pthread_self());

pthread_once(&key_once,once_routine);

}

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

{

pthread_t child_thread_id;

pthread_create(&child_thread_id,NULL,child_thread,NULL);

printf(“I’m father,my id is%u/n”,pthread_self());

pthread_once(&key_once,once_routine);

}

一次性初始化

    有時候我們需要對一些posix變數只進行一次初始化,如線程鍵(我下面會講到)。如果我們進行多次初始化程式就會出現錯誤。

    在傳統的順序編程中,一次性初始化經常通過使用布爾變數來管理。控制變數被靜態初始化為0,而任何依賴於初始化的代碼都能測試該變數。如果變數值仍然為0,則它能實行初始化,然後將變數置為1。以後檢查的代碼將跳過初始化。

    但是在多線程程式設計中,事情就變的複雜的多。如果多個線程並發地執行初始化序列代碼,可能有2個線程發現控制變數為0,並且都實行初始化,而該過程本該僅僅執行一次。

如果我們需要對一個posix變數靜態初始化,可使用的方法是用一個互斥量對該變數的初始話進行控制。但有時候我們需要對該變數進行動態初始化,pthread_once就會方便的多。 

函數原形:

pthread_once_t once_control=PTHREAD_ONCE_INIT;

int pthread_once(pthread_once_t *once_control,void(*init_routine)(void));

參數:

once_control         控制變數

init_routine         初始化函數

傳回值:

若成功返回0,若失敗返回錯誤編號。

 類型為pthread_once_t的變數是一個控制變數。控制變數必須使用PTHREAD_ONCE_INIT宏靜態地初始化。

pthread_once函數首先檢查控制變數,判斷是否已經完成初始化,如果完成就簡單地返回;否則,pthread_once調用初始化函數,並且記錄下初始化被完成。如果在一個線程初始時,另外的線程調用pthread_once,則調用線程等待,直到那個現成完成初始話返回。

下面就是該函數的程式例子: 

#include <pthread.h>

pthread_once_t once=PTHREAD_ONCE_INIT;

pthread_mutex_t mutex; 

void once_init_routine(void) 

{

    int status;

    status=pthread_mutex_init(&mutex,NULL);

    if(status==0)

    printf(“Init success!,My id is %u”,pthread_self());

}

void *child_thread(void *arg)

{

    printf(“I’m child ,My id is %u”,pthread_self());

    pthread_once(&once,once_init_routine);

}

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

{

    pthread_t child_thread_id;

    pthread_create(&child_thread_id,NULL,child_thread,NULL);

    printf(“I’m father,my id is %u”,pthread_self());

    pthread_once(&once_block,once_init_routine);

    pthread_join(child_thread_id,NULL);

}

線程的私人資料

    在進程內的所有線程共用相同的地址空間,任何聲明為靜態或外部的變數,或在進程堆聲明的變數,都可以被進程所有的線程讀寫。那怎樣才能使線程式擁有自己的私人資料呢。

posix提供了一種方法,建立線程鍵。

函數原形:

int pthread_key_create(pthread_key *key,void(*destructor)(void *));

參數:

key           私人資料鍵

destructor    清理函數

傳回值:

若成功返回0,若失敗返回錯誤編號

   第一個參數為指向一個索引值的指標,第二個參數指明了一個destructor函數(清理函數),如果這個參數不為空白,那麼當每個線程結束時,系統將調用這個函數來釋放綁定在這個鍵上的記憶體塊。這個函數常和函數pthread_once一起使用,為了讓這個鍵只被建立一次。函數pthread_once聲明一個初始化函數,第一次調用pthread_once時它執行這個函數,以後的調用將被它忽略。

下面是程式例子: 

#include <pthread.h>

pthread_key_t tsd_key;

pthread_once_t key_once=PTHREAD_ONCE_INIT;

void once_routine(void)

{

int status;

status=pthread_key_create(&tsd_key,NULL);

if(status=0)

    printf(“Key create success! My id is %u/n”,pthread_self());

}

void *child_thread(void *arg)

{

printf(“I’m child,My id is %u/n”,pthread_self());

pthread_once(&key_once,once_routine);

}

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

{

pthread_t child_thread_id;

pthread_create(&child_thread_id,NULL,child_thread,NULL);

printf(“I’m father,my id is%u/n”,pthread_self());

pthread_once(&key_once,once_routine);

}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.