One-time initializations

Some C libraries are designed for dynamic initialization, in which the global initialization for the library is performed when the first procedure in the library is called.

In a single-threaded program, this is usually implemented using a static variable whose value is checked on entry to each routine, as in the following code fragment:

static int isInitialized = 0;
extern void Initialize();

int function()
{
        if (isInitialized == 0) {
                Initialize();
                isInitialized = 1;
        }
        ...
}

For dynamic library initialization in a multithreaded program, a simple initialization flag is not sufficient. This flag must be protected against modification by multiple threads simultaneously calling a library function. Protecting the flag requires the use of a mutex; however, mutexes must be initialized before they are used. Ensuring that the mutex is only initialized once requires a recursive solution to this problem.

To keep the same structure in a multithreaded program, use the pthread_once subroutine. Otherwise, library initialization must be accomplished by an explicit call to a library exported initialization function prior to any use of the library. The pthread_once subroutine also provides an alternative for initializing mutexes and condition variables.

Read the following to learn more about one-time initializations:

One-time initialization object

The uniqueness of the initialization is ensured by the one-time initialization object. It is a variable having the pthread_once_t data type. In AIX® and most other implementations of the threads library, the pthread_once_t data type is a structure.

A one-time initialization object is typically a global variable. It must be initialized with the PTHREAD_ONCE_INIT macro, as in the following example:

static pthread_once_t once_block = PTHREAD_ONCE_INIT;

The initialization can also be done in the initial thread or in any other thread. Several one-time initialization objects can be used in the same program. The only requirement is that the one-time initialization object be initialized with the macro.

One-time initialization routine

The pthread_once subroutine calls the specified initialization routine associated with the specified one-time initialization object if it is the first time it is called; otherwise, it does nothing. The same initialization routine must always be used with the same one-time initialization object. The initialization routine must have the following prototype:
void init_routine();

The pthread_once subroutine does not provide a cancelation point. However, the initialization routine may provide cancelation points, and, if cancelability is enabled, the first thread calling the pthread_once subroutine may be canceled during the execution of the initialization routine. In this case, the routine is not considered as executed, and the next call to the pthread_once subroutine would result in recalling the initialization routine.

It is recommended to use cleanup handlers in one-time initialization routines, especially when performing non-idempotent operations, such as opening a file, locking a mutex, or allocating memory.

One-time initialization routines can be used for initializing mutexes or condition variables or to perform dynamic initialization. In a multithreaded library, the code fragment shown above (void init_routine();) would be written as follows:
static pthread_once_t once_block = PTHREAD_ONCE_INIT;
extern void Initialize();

int function()
{
        pthread_once(&once_block, Initialize);
        ...
}