инициализация One-Time
Компоненты часто предназначены для выполнения задач инициализации при первом вызове, а не при загрузке. Функции одноразовой инициализации гарантируют, что эта инициализация происходит только один раз, даже если несколько потоков могут попытаться инициализации.
Windows Server 2003 и Windows XP: приложения должны обеспечивать собственную синхронизацию для однократной инициализации с помощью межблокированных функций или другого механизма синхронизации. Функции одноразовой инициализации доступны начиная с Windows Vista и Windows Server 2008.
Функции одноразовой инициализации обеспечивают значительные преимущества, чтобы гарантировать, что только один поток выполняет инициализацию:
- Они оптимизированы для скорости.
- Они создают соответствующие барьеры для архитектур процессоров, требующих их.
- Они поддерживают как заблокированную, так и параллельную инициализацию.
- Они избегают внутренней блокировки, чтобы код может работать асинхронно или синхронно.
Система управляет процессом инициализации с помощью непрозрачной INIT_ONCE структуры, содержащей данные и сведения о состоянии. Вызывающий объект выделяет эту структуру и инициализирует его путем вызова InitOnceInitialize (для динамической инициализации структуры) или назначения константы INIT_ONCE_STATIC_INIT переменной структуры (для инициализации структуры статически). Изначально данные, хранящиеся в структуре однократной инициализации, равно NULL, и его состояние неинициализировано.
Однократные структуры инициализации нельзя совместно использовать в процессах.
Поток, выполняющий инициализацию, может при необходимости задать контекст, доступный вызывающей функции после завершения инициализации. Контекст может быть объектом синхронизации или может быть значением или структурой данных. Если контекст является значением, его низкий порядок INIT_ONCE_CTX_RESERVED_BITS должен быть равен нулю. Если контекст является структурой данных, структура данных должна быть DWORD. Контекст возвращается вызывающей функции lpContext выходного параметра InitOnceBeginInitialize или InitOnceExecuteOnce.
Однократная инициализация может выполняться синхронно или асинхронно. Необязательная функция обратного вызова может использоваться для синхронной однократной инициализации.
Синхронная однократная инициализация
В следующих шагах описана синхронная однократная инициализация, которая не использует функцию обратного вызова.
- Первый поток для вызова функции InitOnceBeginInitialize успешно приводит к инициализации единовременной инициализации. Для синхронной однократной инициализации необходимо вызвать InitOnceBeginInitialize без флага INIT_ONCE_ASYNC.
- Последующие потоки, которые пытаются инициализации, блокируются до тех пор, пока первый поток не завершит инициализацию или завершится сбоем. Если первый поток завершается ошибкой, следующий поток может попытаться инициализации и т. д.
- По завершении инициализации поток вызывает функцию InitOnceComplete. Поток может при необходимости создать объект синхронизации (или другие данные контекста) и указать его в параметре lpContext функции InitOnceComplete.
- Если инициализация выполнена успешно, состояние однократной структуры инициализации изменяется на инициализировано, а дескриптор lpContext (если таковой) хранится в структуре инициализации. Последующие попытки инициализации возвращают эти данные контекста. Если инициализация завершается ошибкой, данные null.
Ниже описана синхронная однократная инициализация, которая использует функцию обратного вызова.
- Первый поток, который успешно вызывает функцию InitOnceExecuteOnceOnce, передает указатель на определяемую приложением функцию InitOnceCallback обратного вызова и все данные, необходимые функции обратного вызова. Если вызов выполнен успешно, функция обратного вызова выполняется InitOnceCallback.
- Последующие потоки, которые пытаются инициализации, блокируются до тех пор, пока первый поток не завершит инициализацию или завершится сбоем. Если первый поток завершается ошибкой, следующий поток может попытаться инициализации и т. д.
- После завершения инициализации функция обратного вызова возвращается. Функция обратного вызова может при необходимости создать объект синхронизации (или другие данные контекста) и указать его в параметре Context выходных данных.
- Если инициализация выполнена успешно, состояние однократной структуры инициализации изменяется на инициализированную, а дескриптор контекста контекста (если таковой есть) хранится в структуре инициализации. Последующие попытки инициализации возвращают эти данные контекста. Если инициализация завершается ошибкой, данные null.
Асинхронная однократная инициализация
Ниже описана асинхронная однократная инициализация.
- Если несколько потоков одновременно пытаются начать инициализацию путем вызова InitOnceBeginInitialize с INIT_ONCE_ASYNC, функция выполняется успешно для всех потоков с параметром fPending значение TRUE. При инициализации только один поток будет успешно выполнен; другие одновременные попытки не изменяют состояние инициализации.
- При возвращении InitOnceBeginInitialize параметр fPending указывает состояние инициализации:
- Если fPendingfalse, один поток успешно выполнен при инициализации. Другие потоки должны очистить все созданные ими данные контекста и использовать контекстные данные в lpContext выходном параметре InitOnceBeginInitialize.
- Если fPendingTRUE, инициализация еще не завершена и другие потоки должны продолжаться.
- Каждый поток вызывает функцию InitOnceComplete. Поток может при необходимости создать объект синхронизации (или другие данные контекста) и указать его в параметре lpContextInitOnceComplete.
- При возврате InitOnceComplete возвращается значение возвращаемого значения, указывающее, выполнен ли вызывающий поток при инициализации.
- Если InitOnceComplete успешно, вызывающий поток успешно выполнен при инициализации. Состояние однократной структуры инициализации изменяется на инициализированную, а дескриптор lpContext (если таковой) хранится в структуре инициализации.
- Если InitOnceComplete завершается ошибкой, другой поток успешно выполнен при инициализации. Вызывающий поток должен очистить все созданные данные контекста и вызвать InitOnceBeginInitialize с помощью INIT_ONCE_CHECK_ONLY, чтобы получить все данные контекста, хранящиеся в структуре однократной инициализации.
Вызов One-Time инициализации с нескольких сайтов
Однократная инициализация, защищенная одной INIT_ONCE структурой, может выполняться с нескольких сайтов; Разные обратные вызовы могут передаваться с каждого сайта, а синхронизация с и без обратного вызова может быть смешанной. Инициализация по-прежнему гарантируется успешное выполнение только один раз.
Однако асинхронная и синхронная инициализация не может быть смешанной: после попытки асинхронной инициализации попытка начать синхронную инициализацию завершится ошибкой.
Связанные разделы