Some C libraries are designed for dynamic initialization. That is, 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 multi-threaded 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 multi-threaded program a new subroutine, pthread_once, is provided by the threads library. Otherwise, library initialization must be accomplished by an explicit call to a library exported initialization function prior to any use of the library. This subroutine also provides an alternative for initializing mutexes and condition variables.
Read the following to learn more about one-time initializations:
The uniqueness of the initialization is ensured by an object, the one-time initialization object, or once block. 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.
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 cancellation point. However, the initialization routine may provide cancellation 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. The code fragment shown above would be written in a multi-threaded library as follows:
static pthread_once_t once_block = PTHREAD_ONCE_INIT; extern void Initialize(); int function() { pthread_once(&once_block, Initialize); ... }
Making Complex Synchronization Objects.
List of Threads Advanced Feature Subroutines.