Freigeben über


One-Time Initialisierung

Komponenten sind häufig so konzipiert, dass Initialisierungsaufgaben ausgeführt werden, wenn sie zum ersten Mal aufgerufen werden und nicht, wenn sie geladen werden. Die einmaligen Initialisierungsfunktionen stellen sicher, dass diese Initialisierung nur einmal erfolgt, auch wenn mehrere Threads die Initialisierung versuchen können.

Windows Server 2003 und Windows XP: Anwendungen müssen ihre eigene Synchronisierung für einmalige Initialisierung bereitstellen, indem sie die verriegelten Funktionen oder einen anderen Synchronisierungsmechanismus verwenden. Die einmaligen Initialisierungsfunktionen sind ab Windows Vista und Windows Server 2008 verfügbar.

Die einmaligen Initialisierungsfunktionen bieten erhebliche Vorteile, um sicherzustellen, dass nur ein Thread die Initialisierung durchführt:

  • Sie sind für Geschwindigkeit optimiert.
  • Sie erstellen die entsprechenden Barrieren für Prozessorarchitekturen, die sie erfordern.
  • Sie unterstützen sowohl gesperrte als auch parallele Initialisierung.
  • Sie vermeiden die interne Sperrung, sodass der Code asynchron oder synchron ausgeführt werden kann.

Das System verwaltet den Initialisierungsprozess über eine undurchsichtige INIT_ONCE Struktur, die Daten- und Zustandsinformationen enthält. Der Aufrufer weist diese Struktur zu und initialisiert sie, indem entweder InitOnceInitialize aufgerufen wird (um die Struktur dynamisch zu initialisieren) oder die Konstante INIT_ONCE_STATIC_INIT der Strukturvariablen zuzuweisen (um die Struktur statisch zu initialisieren). Zunächst sind die in der einmaligen Initialisierungsstruktur gespeicherten Daten NULL, und ihr Zustand wird nicht initialisiert.

Einmalige Initialisierungsstrukturen können nicht über Prozesse hinweg gemeinsam genutzt werden.

Der Thread, der die Initialisierung durchführt, kann optional einen Kontext festlegen, der nach Abschluss der Initialisierung für den Aufrufer verfügbar ist. Der Kontext kann ein Synchronisierungsobjekt sein, oder es kann sich um einen Wert oder eine Datenstruktur handeln. Wenn der Kontext ein Wert ist, muss die INIT_ONCE_CTX_RESERVED_BITS der niedrigen Reihenfolge null sein. Wenn der Kontext eine Datenstruktur ist, muss die Datenstruktur DWORD--aligned sein. Der Kontext wird an den Aufrufer im lpContext Ausgabeparameter der InitOnceBeginInitialize oder InitOnceExecuteOnce-Funktion zurückgegeben.

Einmalige Initialisierung kann synchron oder asynchron durchgeführt werden. Eine optionale Rückruffunktion kann für die synchrone einmalige Initialisierung verwendet werden.

Synchrone einmalige Initialisierung

Die folgenden Schritte beschreiben die synchrone einmalige Initialisierung, die keine Rückruffunktion verwendet.

  1. Der erste Thread, der die InitOnceBeginInitialize Funktion aufruft, führt zu einem erfolgreichen Start der einmaligen Initialisierung. Für die synchrone einmalige Initialisierung muss InitOnceBeginInitialize- ohne das INIT_ONCE_ASYNC-Flag aufgerufen werden.
  2. Nachfolgende Threads, die die Initialisierung versuchen, werden blockiert, bis der erste Thread entweder die Initialisierung abgeschlossen oder fehlschlägt. Wenn der erste Thread fehlschlägt, kann der nächste Thread versuchen, die Initialisierung usw. zu versuchen.
  3. Nach Abschluss der Initialisierung ruft der Thread die InitOnceComplete--Funktion auf. Der Thread kann optional ein Synchronisierungsobjekt (oder andere Kontextdaten) erstellen und im lpContext- Parameter der InitOnceComplete--Funktion angeben.
  4. Wenn die Initialisierung erfolgreich ist, wird der Zustand der einmaligen Initialisierungsstruktur in initialisiert und das lpContext- Handle (falls vorhanden) in der Initialisierungsstruktur gespeichert. Nachfolgende Initialisierungsversuche geben diese Kontextdaten zurück. Wenn die Initialisierung fehlschlägt, werden die Daten NULL-.

Die folgenden Schritte beschreiben die synchrone einmalige Initialisierung, die eine Rückruffunktion verwendet.

  1. Der erste Thread, der die InitOnceExecuteOnce-funktion erfolgreich aufruft, übergibt einen Zeiger an eine anwendungsdefinierte InitOnceCallback- Rückruffunktion und alle daten, die von der Rückruffunktion benötigt werden. Wenn der Aufruf erfolgreich ist, wird die InitOnceCallback- Rückruffunktion ausgeführt.
  2. Nachfolgende Threads, die die Initialisierung versuchen, werden blockiert, bis der erste Thread entweder die Initialisierung abgeschlossen oder fehlschlägt. Wenn der erste Thread fehlschlägt, kann der nächste Thread versuchen, die Initialisierung usw. zu versuchen.
  3. Nach Abschluss der Initialisierung wird die Rückruffunktion zurückgegeben. Die Rückruffunktion kann optional ein Synchronisierungsobjekt (oder andere Kontextdaten) erstellen und in seinem Context Ausgabeparameter angeben.
  4. Wenn die Initialisierung erfolgreich ist, wird der Status der einmaligen Initialisierungsstruktur in initialisiert und das Context Handle (falls vorhanden) in der Initialisierungsstruktur gespeichert. Nachfolgende Initialisierungsversuche geben diese Kontextdaten zurück. Wenn die Initialisierung fehlschlägt, werden die Daten NULL-.

Asynchrone einmalige Initialisierung

Die folgenden Schritte beschreiben die asynchrone einmalige Initialisierung.

  1. Wenn mehrere Threads gleichzeitig versuchen, mit der Initialisierung zu beginnen, indem sie InitOnceBeginInitialize mit INIT_ONCE_ASYNCaufruft, wird die Funktion für alle Threads erfolgreich ausgeführt, wobei der parameter "fPending" auf TRUEfestgelegt ist. Bei der Initialisierung ist tatsächlich nur ein Thread erfolgreich; Andere gleichzeitige Versuche ändern den Initialisierungszustand nicht.
  2. Wenn InitOnceBeginInitialize zurückgibt, gibt der parameter fPending den Initialisierungsstatus an:
    • Wenn ausstehendeFALSE-ist, ist bei der Initialisierung ein Thread erfolgreich. Andere Threads sollten alle kontextbezogenen Daten bereinigen, die sie erstellt haben, und die Kontextdaten im lpContext Ausgabeparameter von InitOnceBeginInitializeverwenden.
    • Wenn ausstehendeTRUEist, wurde die Initialisierung noch nicht abgeschlossen, und andere Threads sollten fortgesetzt werden.
  3. Jeder Thread ruft die InitOnceComplete--Funktion auf. Der Thread kann optional ein Synchronisierungsobjekt (oder andere Kontextdaten) erstellen und im lpContext Parameter von InitOnceCompleteangeben.
  4. Wenn InitOnceComplete- zurückgibt, gibt der Rückgabewert an, ob der aufrufende Thread bei der Initialisierung erfolgreich war.
    • Wenn InitOnceComplete- erfolgreich ist, wurde der aufrufende Thread bei der Initialisierung erfolgreich ausgeführt. Der Zustand der einmaligen Initialisierungsstruktur wird in initialisiert und das lpContext- Handle (falls vorhanden) in der Initialisierungsstruktur gespeichert.
    • Wenn InitOnceComplete- fehlschlägt, wurde bei der Initialisierung ein weiterer Thread erfolgreich ausgeführt. Der aufrufende Thread sollte alle kontextbezogenen Daten bereinigen, die er erstellt hat, und InitOnceBeginInitialize mit INIT_ONCE_CHECK_ONLY aufrufen, um alle Kontextdaten abzurufen, die in der einmaligen Initialisierungsstruktur gespeichert sind.

Aufrufen One-Time Initialisierung von mehreren Websites

Einmalige Initialisierung, die durch eine einzelne INIT_ONCE Struktur geschützt wird, kann von mehreren Standorten ausgeführt werden; Ein anderer Rückruf kann von jedem Standort übergeben werden, und die Synchronisierung mit und ohne Rückruf kann gemischt werden. Die Initialisierung ist weiterhin garantiert, dass sie nur einmal erfolgreich ausgeführt wird.

Die asynchrone und synchrone Initialisierung kann jedoch nicht gemischt werden: Nach dem Versuch der asynchronen Initialisierung schlagen Versuche zum Starten der synchronen Initialisierung fehl.

Verwenden One-Time Initialisierungs-