One time initialization of LINUX threads (PTHREAD_ONCE)

 

1. One time initialization  
stay   Linux function list   The common functions in Linux threads are described in, which are explained in detail here   pthread_once   Function and use.

(1) Why does the "one-time initialization concept" appear?  
In fact, in development, many things need to be done only once, no matter what. It is easiest to initialize an application in the main function and before calling anything else that depends on initialization, especially before creating any thread, initialize the data it needs, such as mutexes, condition variables, thread specific data keys, etc.

(2) Static initialization variables are also very convenient. Why pthread_onc   Will appear?  
In Linux thread development, two initialization methods are usually provided for mutexes and conditional variables, namely dynamic initialization and static initialization. For example:

pthread_cond_t cond; 
//Dynamic initialization: pthread_ cond_ init(&cond, NULL);
//Static initialization: pthread_cond_t = PTHREAD_COND_INITIALIZER;

pthread_mutex_t;
//Dynamic initialization: pthread_ mutex_ init(&mutex,NULL);
//Static initialization: pthread_mutex_t = PTHREAD_MUTEX_INITIALIZER;


Why does it appear here   pthread_once   The main reason is that the previous Linux Phread does not support static initialization of a mutex, condition variable, etc  . In this way, to use a mutex, you have to call pthread first_ mutex_ init   Initialize mutex. Moreover, the mutex must be initialized only once, so the initialization call should be in the one-time initialization code. pthread_once solves this recursive problem. When static initialization of mutex is added to the standard, pthread_once is retained as a convenience function. If pthread is used_ Once is convenient, use it, but you don't have to use it.

(3)pthread_ How to use once?  
First, let's take a look   pthread_once   Function prototype:  

/*Make sure to initialize the function init_ Route is called only once, even pthread_once uses the same ONCE_CONTROL
 *The. Once parameter was executed more than ONCE_CONTROL must point to a that is initialized to pthread_ ONCE_ Static or external variables of init
 *Initialization functions may throw exceptions, which is why this function is not marked as__ THROW.
 */
extern int pthread_once (pthread_once_t *__once_control,
             void (*__init_routine) (void)) __nonnull ((1, 2));


According to the definition of this function:  
① First, you need to declare the type   pthread_once_t   And the control variable must use PTHREAD_ONCE_INIT macro to static initialization.  
② A function containing all initialization codes associated with the "pthread_once_t" must be created. Now the thread can call pthread_once at any time, specifying a pointer to a control variable and a pointer to the relevant initialization function.  

Pthread_once function first checks the control variable to determine whether initialization has been completed. If it has been completed, pthread_once simply returns; otherwise, it returns to call the initialization function (without parameters) , and record that the initialization is completed. If another thread also calls pthread_once during the initialization of one thread, the calling thread will block and wait until that thread completes the initialization and returns. In other words, when pthread_once is successfully returned, the call can always be sure that all States have been initialized.

Code 1  
Pthread_once initialization function   The main function of threadOnceInit is to initialize mutex. The use of pthread_once can ensure that it is initialized only once.  
In the thread execution function subThread, pthread_once is called before calling the mutex to ensure that it will exist even if it is not created in the main function.

/*************************************************************************
 * File Name: pthread_once.c
 * Author:    The answer
 * Function:  Other        
 * Mail:      2412799512@qq.com 
 * Created Time: 2018 Sunday, September 9, 2012 12:06:09
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <time.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/epoll.h>
#include <sys/poll.h>
#define STRUCT_INIT(l,r) .l = r
#define CHECK_VARIABLE(l,r) do{if(0 != r){fprintf(stderr,"[%s], err:[%d]\n",l,r);break;}}while(0);

//Macro initializes pthread_once_t control variable
pthread_once_t once = PTHREAD_ONCE_INIT; 
pthread_mutex_t mutex ;
static const int globalVal = 10;

//pthread_once initialization function
void threadOnceInit(){

    int ret = -1;
    ret = pthread_mutex_init(&mutex, NULL);
    CHECK_VARIABLE("pthread_mutex_init error",ret);
    puts("pthread_mutex_init success.");
    return;
}

//Sub thread execution function
void* subThread(void* param){
    printf("subThread to do...\n");
    int ret = -1;
    ret = pthread_once(&once,threadOnceInit);

    CHECK_VARIABLE("pthread_once error",ret);
    ret = pthread_mutex_lock(&mutex);
    CHECK_VARIABLE("pthread_mutex_lock err",ret);
    printf("subThread has clocked the mutex. and globalVal is: [%d]\n",globalVal);
    ret = pthread_mutex_unlock(&mutex);
    CHECK_VARIABLE("pthread_mutex_unlock err.",ret);

    return  NULL;
}

int main(int argc,char **argv)
{
    pthread_t Tid;
    int ret = -1;
    ret = pthread_create(&Tid,NULL,subThread, NULL);
    CHECK_VARIABLE("pthread_create err.",ret);

    ret = pthread_once(&once,threadOnceInit);
    CHECK_VARIABLE("pthread_once err",ret);

    ret = pthread_mutex_lock(&mutex);
    CHECK_VARIABLE("pthread_mutex_lock",ret);

    printf("Main func has locked the mutex.\n");
    ret = pthread_mutex_unlock(&mutex);
    CHECK_VARIABLE("pthread_mutex_unlock",ret);

    ret = pthread_join(Tid,NULL);
    CHECK_VARIABLE("pthread_join",ret);
    return 0;
}

Compilation: gcc pthread_once.c -o a -lpthread  
Execution:. / a  
The results are:

pthread_mutex_init success.
Main func has locked the mutex.
subThread to do...
subThread has clocked the mutex. and globalVal is: [10]

It can be seen from the print result that the main function executes before the sub thread. In the main function, pthread_once is called first. At this time, mutex mutex is successfully initialized. When pthread_once is called again in the sub thread, if it is detected that the initialization operation has been completed, it will immediately return not to execute.

Posted on Sun, 31 Oct 2021 03:46:11 -0400 by webdesco