POSIX Thread之one-time initializition

5.1 一次初始化(One-time initialization)

 

 typedef int pthread_once_t:在bits/pthreadtypes.h中定义
  #define PTHREAD_ONCE_INIT   0   在pthread.h中定义
   pthread_once_t once_control = PTHREAD_ONCE_INIT;
  
   int pthread_once(pthread_once_t *once_control,void(*init_routine)(void));

  
   有些事情,我们需要被做,而且仅仅做一次就够了。当你在程序中需要初始化一个变量时,它常常需要在进入main函数以前就需要被做,在这个时候,调用其它的函数或者变量可能依赖于初始化数据,并且,在一些特殊情况中,创建线程或者创建线程-特殊数据等等,也可能依赖于已经初始化了的mutex。这仅仅是一种特殊情况,但是它存在。
   如果你正在写一个库,你通常不用写得太华丽。但是你必须要确定,在你将要用到你需要的初始化数据时,它应该已经被初始化完成了。采用静态地(statically)初始经一个mutex能够帮你很多,但有时候,你会发现,采用"一 次初始化数据"这一特性,用起来更方便。
   在传统的顺序设计编程中,一次初始化常常用布尔(bootlean)类型来声明。一个控制变量,比如mutex,condition,它被静态的初始化为0,另一些依靠于这个初始化变量的程序检测这个值,如果值仍为0,它将被初始化为1.以后的检查都将跳过这个初始化过程。
   传统的编程中,一次初始化过程存在一些问题。当你使用多线程编程时,它将会很麻烦。如果不只一个线程同时执行这个初始化代码时,两个线程都发现初始化值为0,并且都执行初始化,然而,推测起来看,由于初始化数据的状态是一个被mutex保护起来的共享不变量,因此,它也应该仅仅被执行一次,而不是两次。
   你可以用boolean变量和通过静态初始化mutex,来编写自己的一次性初始化代码。这在大多例子中,都比使用pthread_once更加便利,也更高效。这主要的原因是因为pthread_once不允许在程序开始进行静态的初始化mutex,或者condition,你只能够 把初始化代码增加到pthread_once的init_routine函数中来达到只进行一次初始化的目的。这样做,只是使得pthread_once作为一个标准的库函数来使用时更加方便,有效。但是,记住,如果方便你就用它,而并非非用不可。
 


 程序once.c   示范了如何使用pthread_once来进行一次性初始化
 
 #include <pthread.h>

 

 

#define err_abort(code,text) do { /
    fprintf (stdout, "%s at /"%s/":%d: %s/n", /
        text, __FILE__, __LINE__, strerror (code)); /
    abort (); /
    } while (0)

 

/*必须先静态初始化once_block为PTHREAD_ONCE_INIT ,也就是0*/
pthread_once_t once_block = PTHREAD_ONCE_INIT;
pthread_mutex_t mutex;

/*
 * 一次初始化函数,意思就是无论调用多少次phtead_once,他几乎总是只执行一次
 */
void once_init_routine (void)
{
    int status;

 printf("initilization/n");           ------------------2
    status = pthread_mutex_init (&mutex, NULL);
    if (status != 0)
        err_abort (status, "Init Mutex");
}

/*
 * 线程开始函数,调用pthread_once来执行一次初始化
 */
void *thread_routine (void *arg)
{
    int status;

   printf("%d/n",once_block);
    status = pthread_once (&once_block, once_init_routine);--------1
 printf("%d/n",once_block);
    if (status != 0)
        err_abort (status, "Once init");
    status = pthread_mutex_lock (&mutex);
    if (status != 0)
        err_abort (status, "Lock mutex");
    printf ("thread_routine has locked the mutex./n");
    status = pthread_mutex_unlock (&mutex);
    if (status != 0)
        err_abort (status, "Unlock mutex");
    return NULL;
}

/*主函数*/
int main (int argc, char *argv[])
{
    pthread_t thread_id;
    char *input, buffer[64];
    int status;

    status = pthread_create (&thread_id, NULL, thread_routine, NULL);
    if (status != 0)
        err_abort (status, "Create thread");
  printf("second initilization/n");
  printf("%d/n",once_block);
    status = pthread_once (&once_block, once_init_routine);------------3
    if (status != 0)
        err_abort (status, "Once init");
    status = pthread_mutex_lock (&mutex);
    if (status != 0)
        err_abort (status, "Lock mutex");
    printf ("Main has locked the mutex./n");
    status = pthread_mutex_unlock (&mutex);
    if (status != 0)
        err_abort (status, "Unlock mutex");
    status = pthread_join (thread_id, NULL);
    if (status != 0)
        err_abort (status, "Join thread");
    return 0;
}

程序简单讲解:
 注意1、2、3步骤
 程序开始先静态初始化once_block为0(PTHRAD_ONCE_INIT),并定义mutex。
 然后进入主函数创建线程,执行线程函数thread_routine,thread_routine调用pthread_once来检查
 程序是否已经初始化了mutex,(这里的第1步)如果once_block为0,则调用once_init_routine进行初始化mutex.(这里的第2步)
 然后处理器执行调度pthread_once,也就是第3步,如果pthread_once发现once_block非0,(我运行时once_block为2),则简单的返回,
 并不执行once_init_routine。
  
 归纳起来总结如下:
   要初始化的互斥量或者条件变量等,放在pthread_once的第二个参数,即init_routine指向的函数中。
   pthread_once的第一个参数once_control应该是全局可见的,并且初始值为0,pthread_once依靠检查该值来决定是否
   进行初始化,当once_control被初始化完成之后,值变为非0,并且这个值由phtread_once来进行保护不会被外界改变。
   但经过一次初始化之后,不论再调用多少次pthread_once,pthread_once都只是简单的返回,而不再进行初始化。
   这样做有两个好处是:
   1.在一些复杂的程序中,你可以方便的进行检查你所使用的mutex或者condition等是否已经进行了初始化。而不会增加太多额外的代码
   2.避免了你自己申请的一个比如boolean类型的变量来检查是否已经进行了初始化时,有可能在外部文件中,被恶意破坏,而得到不正确的值
   但不好的地方也是存在的:
   它不允许在程序的开始进行静态的初始化,而是额外增加一个初始化函数(这样做是为了做为一个标准的库函数而被调用)
   如果你在一些简单的程序中使用时,你完全可以自己静态的初始化一个mutex,然后在某处增加一个逻辑判断,而不是非得用phtread_once不可。
   具体视个人情况而定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值