Разовая инициализация
Некоторые библиотеки на языке 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 процедура инициализации будет вызвана повторно.
При создании функций разовой инициализации, особенно выполняющих неидемпотентные операции, такие как открытие файла, установка взаимной блокировки или выделение памяти, рекомендуется регистрировать функции очистки.
void init_routine();) будет выглядеть следующим
образом:
static pthread_once_t once_block = PTHREAD_ONCE_INIT;
extern void Initialize();
int function()
{
pthread_once(&once_block, Initialize);
...
}