pthread_once从APUE的角度来看,来源于线程的私有数据。线程的私有数据需要使用一个pthread_key_create()创建一个pthread_key_t键值,这个键值需要被进程中的所有线程使用。pthread_key_create()函数一般写在线程函数中,而且需要确保这个函数只被执行一次,为防止不同的线程竞争调用pthread_key_create()函数从而导致不同的线程访问到不同的pthread_key_t键值,提出了pthread_once。pthread_once能够保证initfn只被调用一次,所以可以将initfn换为pthread_key_create()。
#include <pthread.h>
pthread_once_t initflag = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *initflag, void (*initfn)(void));
initflag必须是一个非本地变量。
pthread_once在被一个线程A调用时,如果另一个线程B也要调用pthread_once,那么该线程B就会等待线程A调用完pthread_once。下面是一段程序说明这个问题:
#include <pthread.h>
#include <stdio.h>
#include <unistd.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\n", pthread_self());
}
void *child_thread(void *arg)
{
printf("I'm child, My id is %u\n",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\n",pthread_self());
pthread_once(&once,once_init_routine);
printf("wait for the child pthread_once\n");
}
结果如下:
I'm father, my id is 3488159552
I'm child, My id is 3471374080
Init success!,My id is 3488159552
wait for the child pthread_once