Initialisation One-Time
Les composants sont souvent conçus pour effectuer des tâches d’initialisation lorsqu’ils sont appelés pour la première fois, plutôt que lorsqu’ils sont chargés. Les fonctions d’initialisation unique garantissent que cette initialisation ne se produit qu’une seule fois, même lorsque plusieurs threads peuvent tenter l’initialisation.
Windows Server 2003 et Windows XP : Applications doivent fournir leur propre synchronisation pour l’initialisation ponctuelle à l’aide des fonctions interblocées ou d’autres mécanismes de synchronisation. Les fonctions d’initialisation ponctuelles sont disponibles à partir de Windows Vista et Windows Server 2008.
Les fonctions d’initialisation ponctuelle offrent des avantages significatifs pour s’assurer qu’un seul thread effectue l’initialisation :
- Ils sont optimisés pour la vitesse.
- Ils créent les obstacles appropriés sur les architectures de processeur qui les nécessitent.
- Ils prennent en charge l’initialisation verrouillée et parallèle.
- Ils évitent le verrouillage interne afin que le code puisse fonctionner de manière asynchrone ou synchrone.
Le système gère le processus d’initialisation via une structure de INIT_ONCE opaque qui contient des données et des informations d’état. L’appelant alloue cette structure et l’initialise en appelant InitOnceInitialize (pour initialiser la structure dynamiquement) ou en affectant la constante INIT_ONCE_STATIC_INIT à la variable de structure (pour initialiser la structure de façon statique). Initialement, les données stockées dans la structure d’initialisation unique sont NULL et leur état n’est pas initialisé.
Les structures d’initialisation ponctuelles ne peuvent pas être partagées entre les processus.
Le thread qui effectue l’initialisation peut éventuellement définir un contexte disponible pour l’appelant une fois l’initialisation terminée. Le contexte peut être un objet de synchronisation ou il peut s’agir d’une valeur ou d’une structure de données. Si le contexte est une valeur, son INIT_ONCE_CTX_RESERVED_BITS de faible ordre doit être égal à zéro. Si le contexte est une structure de données, la structure de données doit être DWORDalignée. Le contexte est retourné à l’appelant dans le paramètre de sortie lpContext du InitOnceBeginInitialize ou fonction InitOnceExecuteOnce.
L’initialisation à usage unique peut être effectuée de manière synchrone ou asynchrone. Une fonction de rappel facultative peut être utilisée pour l’initialisation ponctuelle synchrone.
Initialisation ponctuelle synchrone
Les étapes suivantes décrivent l’initialisation ponctuelle synchrone qui n’utilise pas de fonction de rappel.
- Le premier thread à appeler la fonction InitOnceBeginInitialize entraîne le début de l’initialisation ponctuelle. Pour une initialisation ponctuelle synchrone, InitOnceBeginInitialize doit être appelée sans l’indicateur de INIT_ONCE_ASYNC.
- Les threads suivants qui tentent d’initialiser sont bloqués jusqu’à ce que le premier thread termine l’initialisation ou échoue. Si le premier thread échoue, le thread suivant est autorisé à tenter l’initialisation, et ainsi de suite.
- Une fois l’initialisation terminée, le thread appelle la fonction InitOnceComplete. Le thread peut éventuellement créer un objet de synchronisation (ou d’autres données de contexte) et le spécifier dans le paramètre lpContext de la fonction InitOnceComplete.
- Si l’initialisation réussit, l’état de la structure d’initialisation unique est remplacé par initialisé et le handle lpContext (le cas échéant) est stocké dans la structure d’initialisation. Les tentatives d’initialisation suivantes retournent ces données de contexte. Si l’initialisation échoue, les données sont null.
Les étapes suivantes décrivent l’initialisation ponctuelle synchrone qui utilise une fonction de rappel.
- Le premier thread pour appeler la fonction InitOnceExecuteOnce passe un pointeur vers une fonction de rappel initOnceCallback définie par l’application fonction de rappel et toutes les données requises par la fonction de rappel. Si l’appel réussit, la fonction de rappel InitOnceCallback s’exécute.
- Les threads suivants qui tentent d’initialiser sont bloqués jusqu’à ce que le premier thread termine l’initialisation ou échoue. Si le premier thread échoue, le thread suivant est autorisé à tenter l’initialisation, et ainsi de suite.
- Une fois l’initialisation terminée, la fonction de rappel retourne. La fonction de rappel peut éventuellement créer un objet de synchronisation (ou d’autres données de contexte) et le spécifier dans son paramètre de sortie Context.
- Si l’initialisation réussit, l’état de la structure d’initialisation unique est remplacé par initialisé et le handle Context (le cas échéant) est stocké dans la structure d’initialisation. Les tentatives d’initialisation suivantes retournent ces données de contexte. Si l’initialisation échoue, les données sont null.
Initialisation asynchrone à usage unique
Les étapes suivantes décrivent l’initialisation ponctuelle asynchrone.
- Si plusieurs threads tentent simultanément de commencer l’initialisation en appelant InitOnceBeginInitialize avec INIT_ONCE_ASYNC, la fonction réussit pour tous les threads avec le paramètre fPending défini sur TRUE. Un seul thread réussit réellement à l’initialisation ; Les autres tentatives simultanées ne modifient pas l’état d’initialisation.
- Lorsque InitOnceBeginInitialize retourne, le paramètre fPending indique l’état d’initialisation :
- Si imminente est faux, un thread a réussi à l’initialisation. D’autres threads doivent nettoyer les données de contexte qu’ils ont créées et utiliser les données de contexte dans le paramètre de sortie lpContext de InitOnceBeginInitialize.
- Si imminente est TRUE, l’initialisation n’a pas encore été terminée et d’autres threads doivent continuer.
- Chaque thread appelle la fonction InitOnceComplete. Le thread peut éventuellement créer un objet de synchronisation (ou d’autres données de contexte) et le spécifier dans le paramètre lpContext de InitOnceComplete.
- Lorsque InitOnceComplete retourne, sa valeur de retour indique si le thread appelant a réussi à l’initialisation.
- Si InitOnceComplete réussit, le thread appelant a réussi à l’initialisation. L’état de la structure d’initialisation unique est remplacé par initialisé et le handle lpContext (le cas échéant) est stocké dans la structure d’initialisation.
- Si InitOnceComplete échoue, un autre thread a réussi à l’initialisation. Le thread appelant doit nettoyer toutes les données de contexte qu’il a créées et appeler InitOnceBeginInitialize avec INIT_ONCE_CHECK_ONLY pour récupérer les données de contexte stockées dans la structure d’initialisation à usage unique.
Appel One-Time initialisation à partir de plusieurs sites
Une initialisation ponctuelle protégée par une seule structure de INIT_ONCE peut être effectuée à partir de plusieurs sites ; Différents rappels peuvent être transmis à partir de chaque site, et la synchronisation avec et sans rappel peut être mixte. L’initialisation est toujours garantie d’effectuer correctement une seule fois.
Toutefois, l’initialisation asynchrone et synchrone ne peut pas être mixte : une fois l’initialisation asynchrone tentée, les tentatives de démarrage de l’initialisation synchrone échouent.
Rubriques connexes
-
utiliser One-Time d’initialisation