initialisatie van One-Time
Onderdelen zijn vaak ontworpen om initialisatietaken uit te voeren wanneer ze voor het eerst worden aangeroepen, in plaats van wanneer ze worden geladen. De eenmalige initialisatiefuncties zorgen ervoor dat deze initialisatie slechts één keer plaatsvindt, zelfs wanneer meerdere threads de initialisatie kunnen proberen.
Windows Server 2003 en Windows XP: Toepassingen moeten hun eigen synchronisatie bieden voor eenmalige initialisatie met behulp van de functies die zijn gekoppeld of een ander synchronisatiemechanisme. De eenmalige initialisatiefuncties zijn beschikbaar vanaf Windows Vista en Windows Server 2008.
De eenmalige initialisatiefuncties bieden aanzienlijke voordelen om ervoor te zorgen dat slechts één thread de initialisatie uitvoert:
- Ze zijn geoptimaliseerd voor snelheid.
- Ze creëren de juiste barrières voor processorarchitecturen waarvoor ze nodig zijn.
- Ze ondersteunen zowel vergrendelde als parallelle initialisatie.
- Ze voorkomen interne vergrendeling, zodat de code asynchroon of synchroon kan werken.
Het systeem beheert het initialisatieproces via een ondoorzichtige INIT_ONCE structuur die gegevens en statusinformatie bevat. De aanroeper wijst deze structuur toe en initialiseert deze door InitOnceInitialize aan te roepen (om de structuur dynamisch te initialiseren) of door de constante INIT_ONCE_STATIC_INIT toe te wijzen aan de structuurvariabele (om de structuur statisch te initialiseren). In eerste instantie zijn de gegevens die zijn opgeslagen in de eenmalige initialisatiestructuur NULL en zijn status niet geïnitialiseerd.
Eenmalige initialisatiestructuren kunnen niet worden gedeeld tussen processen.
De thread die de initialisatie uitvoert, kan eventueel een context instellen die beschikbaar is voor de aanroeper nadat de initialisatie is voltooid. De context kan een synchronisatieobject zijn of kan een waarde of gegevensstructuur zijn. Als de context een waarde is, moet de lage volgorde INIT_ONCE_CTX_RESERVED_BITS nul zijn. Als de context een gegevensstructuur is, moet de gegevensstructuur worden DWORD-uitgelijnd. De context wordt geretourneerd naar de aanroeper in de lpContext uitvoerparameter van de InitOnceBeginInitialize of InitOnceExecuteOnce functie.
Eenmalige initialisatie kan synchroon of asynchroon worden uitgevoerd. Een optionele callback-functie kan worden gebruikt voor synchrone eenmalige initialisatie.
Synchrone eenmalige initialisatie
In de volgende stappen worden synchrone eenmalige initialisatie beschreven die geen callback-functie gebruikt.
- De eerste thread voor het aanroepen van de InitOnceBeginInitialize functie zorgt ervoor dat eenmalige initialisatie begint. Voor synchrone eenmalige initialisatie moet InitOnceBeginInitialize- worden aangeroepen zonder de vlag INIT_ONCE_ASYNC.
- Volgende threads die proberen te initialiseren, worden geblokkeerd totdat de eerste thread de initialisatie voltooit of mislukt. Als de eerste thread mislukt, mag de volgende thread proberen de initialisatie uit te voeren, enzovoort.
- Wanneer de initialisatie is voltooid, roept de thread de functie InitOnceComplete aan. De thread kan desgewenst een synchronisatieobject (of andere contextgegevens) maken en opgeven in de parameter lpContext van de functie InitOnceComplete.
- Als de initialisatie slaagt, wordt de status van de eenmalige initialisatiestructuur gewijzigd in geïnitialiseerd en wordt de lpContext handle (indien aanwezig) opgeslagen in de initialisatiestructuur. Volgende initialisatiepogingen retourneren deze contextgegevens. Als de initialisatie mislukt, worden de gegevens NULL-.
In de volgende stappen worden synchrone eenmalige initialisatie beschreven die gebruikmaakt van een callback-functie.
- De eerste thread voor het aanroepen van de InitOnceExecuteOnce functie geeft een aanwijzer door aan een door de toepassing gedefinieerde InitOnceCallback-functie callback-functie en eventuele gegevens die nodig zijn voor de callback-functie. Als de aanroep slaagt, wordt de InitOnceCallback- callback-functie uitgevoerd.
- Volgende threads die proberen te initialiseren, worden geblokkeerd totdat de eerste thread de initialisatie voltooit of mislukt. Als de eerste thread mislukt, mag de volgende thread proberen de initialisatie uit te voeren, enzovoort.
- Wanneer de initialisatie is voltooid, wordt de callback-functie geretourneerd. De callback-functie kan eventueel een synchronisatieobject (of andere contextgegevens) maken en dit opgeven in de Context uitvoerparameter.
- Als de initialisatie slaagt, wordt de status van de eenmalige initialisatiestructuur gewijzigd in geïnitialiseerd en wordt de Context handle (indien aanwezig) opgeslagen in de initialisatiestructuur. Volgende initialisatiepogingen retourneren deze contextgegevens. Als de initialisatie mislukt, worden de gegevens NULL-.
Asynchrone eenmalige initialisatie
In de volgende stappen wordt asynchrone eenmalige initialisatie beschreven.
- Als meerdere threads tegelijkertijd proberen te initialiseren door InitOnceBeginInitialize aan te roepen met INIT_ONCE_ASYNC, slaagt de functie voor alle threads met de parameter fPending ingesteld op TRUE. Slechts één thread slaagt bij de initialisatie. bij andere gelijktijdige pogingen wordt de initialisatiestatus niet gewijzigd.
- Wanneer InitOnceBeginInitialize retourneert, geeft de parameter fPending de initialisatiestatus aan:
- Als fPending- is ONWAAR, is er één thread geslaagd bij de initialisatie. Andere threads moeten alle contextgegevens die ze hebben gemaakt opschonen en de contextgegevens in de lpContext uitvoerparameter van InitOnceBeginInitializegebruiken.
- Als fPending- is TRUE, is initialisatie nog niet voltooid en moeten andere threads worden voortgezet.
- Elke thread roept de functie InitOnceComplete aan. De thread kan desgewenst een synchronisatieobject (of andere contextgegevens) maken en opgeven in de parameter lpContext parameter van InitOnceComplete.
- Wanneer InitOnceComplete retourneert, geeft de retourwaarde aan of de aanroepende thread is geslaagd bij de initialisatie.
- Als InitOnceComplete slaagt, is de aanroepende thread geslaagd bij de initialisatie. De status van de eenmalige initialisatiestructuur wordt gewijzigd in geïnitialiseerd en de lpContext handle (indien aanwezig) wordt opgeslagen in de initialisatiestructuur.
- Als InitOnceComplete- mislukt, is een andere thread geslaagd bij de initialisatie. De aanroepende thread moet alle contextgegevens die zijn gemaakt opschonen en InitOnceBeginInitialize opschonen met INIT_ONCE_CHECK_ONLY om contextgegevens op te halen die zijn opgeslagen in de eenmalige initialisatiestructuur.
One-Time initialisatie vanaf meerdere sites aanroepen
Eenmalige initialisatie die wordt bewaakt door één INIT_ONCE structuur kan worden uitgevoerd vanaf meerdere sites; verschillende callback kan worden doorgegeven vanaf elke site en synchronisatie met en zonder callback kan worden gemengd. Initialisatie wordt nog steeds gegarandeerd slechts één keer uitgevoerd.
Asynchrone en synchrone initialisatie kunnen echter niet worden gemengd: zodra asynchrone initialisatie is geprobeerd, mislukken pogingen om synchrone initialisatie te starten.
Verwante onderwerpen