一次性初始化
有時候我們需要對一些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);
}