一、为什么要使用一次性初始化
    有些事需要且只能执行一次(比如互斥量初始化)。通常当初始化应用程序时,可以比较容易地将其放在main函数中。但当你写一个库函数时,
    就不能在main里面初始化了,你可以用静态初始化,但使用一次初始(pthread_once_t)会比较容易些。

二、如何进行一次性初始化
    1、首先要定义一个pthread_once_t变量,这个变量要用宏PTHREAD_ONCE_INIT初始化。然后创建一个与控制变量相关的初始化函数
    pthread_once_t once_control = PTHREAD_ONCE_INIT;
    void init_routine()
    {
         //初始化互斥量
         //初始化读写锁
         ......
    }


    2、接下来就可以在任何时刻调用pthread_once函数
    int pthread_once(pthread_once_t* once_control, void (*init_routine)(void));
    功能:本函数使用初值为PTHREAD_ONCE_INIT的once_control变量保证init_routine()函数在本进程执行序列中仅执行一次。在多线程编程
    环境下,尽管pthread_once()调用会出现在多个线程中,init_routine()函数仅执行一次,究竟在哪个线程中执行是不定的,是由内核调度来决定。


    3、Linux Threads使用互斥锁和条件变量保证由pthread_once()指定的函数执行且仅执行一次。实际"一次性函数"的执行状态有三种:
        NEVER(0)、IN_PROGRESS(1)、DONE (2),用once_control来表示pthread_once()的执行状态:
    1)、如果once_control初值为0,那么 pthread_once从未执行过,init_routine()函数会执行。
    2)、如果once_control初值设为1,则由于所有pthread_once()都必须等待其中一个激发"已执行一次"信号, 因此所有pthread_once ()都会陷入永久
        的等待中,init_routine()就无法执行
    3)、如果once_control设为2,则表示pthread_once()函数已执行过一次,从而所有pthread_once()都会立即   返回,init_routine()就没有机会执行
        当pthread_once函数成功返回,once_control就会被设置为2

三、手册
PTHREAD_ONCE(3P)           POSIX Programmer’s Manual          PTHREAD_ONCE(3P)

PROLOG
       This  manual page is part of the POSIX Programmer’s Manual.  The Linux implementation of this interface may differ (con-
       sult the corresponding Linux manual page for details of Linux behavior), or the interface  may  not  be  implemented  on
       Linux.
         //这只是POSIX的手册,Linux对这个接口的实现可能不一样,或者有的根本没有实现这个接口

NAME
       pthread_once - dynamic package initialization
        //动态初始化

SYNOPSIS
       #include
        //头文件

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


DESCRIPTION
       The first call to pthread_once() by any thread in a process, with a given once_control, shall call the init_routine with
       no arguments. Subsequent calls of pthread_once() with the same once_control shall not call the init_routine.  On  return
       from  pthread_once(),  init_routine shall have completed. The once_control parameter shall determine whether the associ-
       ated initialization routine has been called.
        //第一次调用 pthread_once()的线程会调用初始化例程,这个初始化函数没有参数,当再次调用 pthread_once()的时候,初始化
        //例程将不被调用。当 pthread_once()返回的时候,初始化例程就会完成,once_control变量将会决定初始化例程是否已经被调用

       The pthread_once() function is not a cancellation point. However, if init_routine is a cancellation point  and  is  can-
       celed, the effect on once_control shall be as if pthread_once() was never called.
        // pthread_once()不是一个取消点。但是初始化例程是一个取消点,如果它被取消,那么 pthread_once()就好像从未调用过

       The constant PTHREAD_ONCE_INIT is defined in the header.
        //PTHREAD_ONCE_INIT定义在头文件pthread.h中

       The  behavior  of  pthread_once()  is  undefined if once_control has automatic storage duration or is not initialized by
       PTHREAD_ONCE_INIT.
        // pthread_once()的行为是未知的,如果once_control没有被初始化

RETURN VALUE
       Upon successful completion, pthread_once() shall return zero; otherwise, an error number shall be returned  to  indicate
       the error.
        //成功返回0 ,失败返回错误码

ERRORS
       The pthread_once() function may fail if:
        // pthread_once()在以下情况会失败

       EINVAL If either once_control or init_routine is invalid.
                    //once_control变量或者初始化例程是无效的

       The pthread_once() function shall not return an error code of [EINTR].
        //不会返回EINTR

四、实例
1、一次性初始化的验证

点击(此处)折叠或打开

  1. /*DATE:            2015-4-15
  2.  *AUTHOR:        DDDDD
  3.  *DESCRIPTION:    一次性初始化
  4.     int pthread_once(pthread_once_t* once_control, void (*init_routine)(void));
  5.     如果once_control为0,init_routine()就会执行
  6.     pthread_once()成功返回之后,once_control会变为2
  7.  */

  8. #include "apue.h"

  9. pthread_once_t once = 2;
  10. pthread_t tid;

  11. void thread_init()
  12. {
  13.     printf("I'm in thread 0x%x\n", tid);

  14. }


  15. void *thread_fun1(void *arg)
  16. {
  17.     tid = pthread_self();
  18.     printf("I'm thread 0x%x\n", tid);
  19.     printf("once is %d\n", once);
  20.     pthread_once(&once, thread_init);
  21.     printf("once is %d\n", once);

  22.     return NULL;
  23. }

  24. void *thread_fun2(void *arg)
  25. {
  26.     sleep(2);
  27.     tid = pthread_self();
  28.     printf("I'm thread 0x%x\n", tid);
  29.     pthread_once(&once, thread_init);

  30.     return NULL;
  31. }

  32. int main()
  33. {
  34.     pthread_t tid1, tid2;
  35.     int err;

  36.     err = pthread_create(&tid1, NULL, thread_fun1, NULL);
  37.     if(err != 0)
  38.     {
  39.         printf("create new thread 1 failed\n");
  40.         return ;
  41.     }
  42.     err = pthread_create(&tid2, NULL, thread_fun2, NULL);
  43.     if(err != 0)
  44.     {
  45.         printf("create new thread 1 failed\n");
  46.         return ;
  47.     }


  48.     pthread_join(tid1, NULL);
  49.     pthread_join(tid2, NULL);

  50.     return 0;
  51. }
2、将互斥量的初始化,使用pthread_once来实现

点击(此处)折叠或打开

  1. /*DATA:            2015-4-20
  2.  *AUTHOR;        WJ
  3.  *DESCRIPTION:    使用多线程对一个队列进行增加和减少,增加操作是一个线程,删除操作是一个线程
  4.  *    
  5.  */
  6. #include "apue.h"

  7. pthread_mutex_t mutex;
  8. pthread_once_t once = PTHREAD_ONCE_INIT;

  9. struct queue{
  10.     int len;
  11.     int write_pos;
  12.     int read_pos;
  13.     int data[50];
  14. };

  15. //互斥量初始化函数
  16. void mutex_init()
  17. {
  18.     int err;
  19.     err = pthread_mutex_init(&mutex, NULL);
  20.     if(err)
  21.     {
  22.         printf("mutex init failed\n");
  23.         return;
  24.     }
  25. }

  26. //队列初始化
  27. struct queue *queue_init()
  28. {
  29.     struct queue *que;
  30.     //申请内存
  31.     que = (struct queue *)malloc(sizeof(struct queue));
  32.     if(que ==NULL)
  33.     {
  34.         printf("malloc failed\n");
  35.         return;
  36.     }

  37.     //初始化
  38.     que->len = 0;
  39.     que->write_pos = 0;
  40.     que->read_pos = 0;

  41.     return que;
  42. }

  43. void queue_destroy(struct queue *que)
  44. {
  45.     //销毁互斥量和que
  46.     pthread_mutex_destroy(&mutex);
  47.     free(que);
  48. }

  49. void *queue_add(void *arg)
  50. {
  51.     //对互斥量进行一次性初始化
  52.     pthread_once(&once, mutex_init);
  53.     struct queue *que = (struct queue *)arg;
  54.     int buf=0;
  55.     while(buf<50)
  56.     {
  57.         pthread_mutex_lock(&mutex);
  58.         que->data[que->write_pos] = buf;
  59.         que->write_pos ++;
  60.         que->len ++;
  61.         buf++;
  62.         printf("write data %d to queue\n", que->data[que->write_pos -1]);

  63.         pthread_mutex_unlock(&mutex);
  64.         sleep(1);
  65.     }
  66. }

  67. void *queue_del(void *arg)
  68. {
  69.     //    对互斥量进行一次性初始化
  70.     pthread_once(&once, mutex_init);
  71.     struct queue *que = (struct queue *)arg;
  72.     int buf=0;
  73.     while(1)
  74.     {
  75.         sleep(2);
  76.         pthread_mutex_lock(&mutex);
  77.         buf = que->data[que->read_pos];
  78.         que->read_pos ++;
  79.         if(que->len -- == 0)
  80.         {
  81.             printf("queue is empty\n");
  82.             return;
  83.         }
  84.         buf++;
  85.         printf("read data %d from queue\n", que->data[que->read_pos -1]);
  86.         pthread_mutex_unlock(&mutex);
  87.     }
  88. }

  89. int main()
  90. {
  91.     pthread_t tid1, tid2;
  92.     int err;
  93.     struct queue *que;

  94.     //队列初始化
  95.     que = queue_init();

  96.     err = pthread_create(&tid1, NULL, queue_add, (void *)que);
  97.     if(err)
  98.     {
  99.         printf("create add thread failed\n");
  100.         queue_destroy(que);
  101.         return;
  102.     }

  103.     err = pthread_create(&tid2, NULL, queue_del, (void *)que);
  104.     if(err)
  105.     {
  106.         printf("create del thread failed\n");
  107.         queue_destroy(que);
  108.         return;
  109.     }

  110.     //等待增加和删除操作完成
  111.     pthread_join(tid1, NULL);
  112.     pthread_join(tid2, NULL);

  113.     //销毁
  114.     queue_destroy(que);
  115. }







09-08 15:49