一次性初始化
一些 C 库是为动态初始化设计的,这些库的全局初始化是在调用库中的第一个过程时执行的。
在单线程程序中,这通常通过使用静态变量(在每个例程的入口检查其值)实现,如下面的代码片段所示:
static int isInitialized = 0;
extern void Initialize();
int function()
{
if (isInitialized == 0) {
Initialize();
isInitialized = 1;
}
...
}对于多线程程序中的动态库初始化,单个初始化标记是不够的。 必须保护此标记不被同时调用库函数的多个线程更改。 保护标记需要使用互斥对象;但是在使用互斥对象之前必须将其初始化。 确保互斥对象仅被初始化一次需要递归解决方案。
要在多线程程序中保持相同的结构,请使用 pthread_once 子例程。 否则,库初始化必须通过在使用库之前显式调用库导出初始化函数来完成。 pthread_once 子例程还提供初始化互斥对象和条件变量的其他方法。
请阅读下面的内容,了解更多有关一次性初始化的信息:
一次性初始化对象
初始化的唯一性通过一次性初始化对象确保。 此变量的数据类型为 pthread_once_t。 在AIX和线程库的大多数其他实现中,pthread_once_t数据类型是一个结构体。
一次性初始化对象是典型的全局变量。 必须使用 PTHREAD_ONCE_INIT 宏对其进行初始化,如以下示例中所示:
static pthread_once_t once_block = PTHREAD_ONCE_INIT;初始化还能在初始线程或者其他任何线程中执行。 可在同一个程序中使用多个一次性初始化对象。 唯一的要求是一次性初始化对象必须使用宏初始化。
一次性初始化例程
void init_routine();pthread_once 子例程不提供取消点。 但是,初始化例程可能提供取消点,如果启用了可取消,那么调用 pthread_once 子例程的第一个线程可能在执行初始化例程期间被取消。 在这种情况下,并不认为该例程被执行,下一次调用 pthread_once 子例程将会重新调用初始化例程。
建议在一次性初始化例程中使用清除处理程序,特别是执行非 idempotent 操作时,例如,打开文件、锁定互斥对象或者分配内存。
void
init_routine();) 将按如下所示编写:static pthread_once_t once_block = PTHREAD_ONCE_INIT;
extern void Initialize();
int function()
{
pthread_once(&once_block, Initialize);
...
}