Sdílet prostřednictvím


Inicializace One-Time

Komponenty jsou často navržené tak, aby prováděly úlohy inicializace při prvním zavolání, a ne při jejich načtení. Jednorázové inicializační funkce zajišťují, že k této inicializaci dojde pouze jednou, a to i v případě, že se inicializace může pokusit inicializovat více vláken.

Windows Server 2003 a Windows XP: aplikace musí poskytovat vlastní synchronizaci pro jednorázovou inicializaci pomocí vzájemně uzamčených funkcí nebo jiného synchronizačního mechanismu. Jednorázové inicializační funkce jsou k dispozici od systémů Windows Vista a Windows Server 2008.

Jednorázové inicializační funkce poskytují významné výhody, které zajistí, že inicializaci provede pouze jedno vlákno:

  • Jsou optimalizované pro rychlost.
  • Vytvářejí odpovídající bariéry v architekturách procesorů, které je vyžadují.
  • Podporují uzamčenou i paralelní inicializaci.
  • Vyhýbají se internímu uzamčení, aby kód fungoval asynchronně nebo synchronně.

Systém spravuje proces inicializace prostřednictvím neprůrazné INIT_ONCE struktury, která obsahuje data a informace o stavu. Volající přiděluje tuto strukturu a inicializuje ji buď voláním InitOnceInitialize (k dynamické inicializaci struktury) nebo přiřazením konstanty INIT_ONCE_STATIC_INIT proměnné struktury (pro inicializaci struktury staticky). Zpočátku jsou data uložená v jednorázové inicializační struktuře null a její stav není inicializován.

Jednorázové inicializační struktury nelze sdílet napříč procesy.

Vlákno, které provádí inicializaci, může volitelně nastavit kontext, který je k dispozici volajícímu po dokončení inicializace. Kontextem může být synchronizační objekt nebo to může být hodnota nebo datová struktura. Pokud je kontext hodnotou, musí být její INIT_ONCE_CTX_RESERVED_BITS nízkého pořadí nula. Pokud je kontext datovou strukturou, musí být datová struktura DWORDzarovnaná. Kontext se vrátí volajícímu v lpContext výstupní parametr InitOnceBeginInitialize nebo InitOnceExecuteOnce funkce.

Jednorázová inicializace se dá provádět synchronně nebo asynchronně. Volitelnou funkci zpětného volání lze použít pro synchronní jednorázovou inicializaci.

Synchronní jednorázová inicializace

Následující kroky popisují synchronní jednorázovou inicializaci, která nepoužívá funkci zpětného volání.

  1. První vlákno pro volání InitOnceBeginInitialize funkce úspěšně způsobí, že jednorázová inicializace začne. Pro synchronní jednorázovou inicializaci InitOnceBeginInitialize musí být volána bez příznaku INIT_ONCE_ASYNC.
  2. Následná vlákna, která se pokusí inicializovat, se zablokují, dokud první vlákno nedokonjí inicializaci nebo selže. Pokud první vlákno selže, může se další vlákno pokusit o inicializaci atd.
  3. Po dokončení inicializace vlákno volá InitOnceComplete funkce. Vlákno může volitelně vytvořit objekt synchronizace (nebo jiná kontextová data) a zadat ho v lpContext parametr InitOnceComplete funkce.
  4. Pokud inicializace proběhne úspěšně, stav jednorázové inicializační struktury se změní na inicializaci a lpContext popisovač (pokud existuje) je uložen v inicializační struktuře. Následné pokusy o inicializaci vrátí tato kontextová data. Pokud inicializace selže, data se null.

Následující kroky popisují synchronní jednorázovou inicializaci, která používá funkci zpětného volání.

  1. První vlákno, které úspěšně zavolá Funkce InitOnceExecuteOnce předá ukazatel na funkci definovanou aplikací InitOnceCallback funkci zpětného volání a všechna data vyžadovaná funkcí zpětného volání. Pokud volání proběhne úspěšně, spustí se InitOnceCallback funkce zpětného volání.
  2. Následná vlákna, která se pokusí inicializovat, se zablokují, dokud první vlákno nedokonjí inicializaci nebo selže. Pokud první vlákno selže, může se další vlákno pokusit o inicializaci atd.
  3. Po dokončení inicializace vrátí funkce zpětného volání. Funkce zpětného volání může volitelně vytvořit synchronizační objekt (nebo jiná kontextová data) a zadat ho ve svém Context výstupním parametru.
  4. Pokud inicializace proběhne úspěšně, změní se stav jednorázové inicializační struktury na inicializaci a Kontext popisovač (pokud existuje) je uložen ve struktuře inicializace. Následné pokusy o inicializaci vrátí tato kontextová data. Pokud inicializace selže, data se null.

Asynchronní jednorázová inicializace

Následující kroky popisují asynchronní jednorázovou inicializaci.

  1. Pokud se více vláken současně pokusí zahájit inicializaci voláním InitOnceBeginInitialize s INIT_ONCE_ASYNC, funkce bude úspěšná pro všechna vlákna s fPending parametr nastaven na TRUE. Při inicializaci bude ve skutečnosti úspěšné pouze jedno vlákno; jiné souběžné pokusy nemění stav inicializace.
  2. Když InitOnceBeginInitialize vrátí, fPending parametr inicializuje stav inicializace:
    • Pokud fPending je false, jedno vlákno bylo úspěšné při inicializaci. Ostatní vlákna by měla vyčistit všechna kontextová data, která vytvořili, a použít kontextová data v lpContext výstupní parametr InitOnceBeginInitialize.
    • Pokud fPending je true, inicializace ještě nebyla dokončena a další vlákna by měla pokračovat.
  3. Každé vlákno volá funkci InitOnceComplete. Vlákno může volitelně vytvořit objekt synchronizace (nebo jiná kontextová data) a zadat ho v lpContext parametr InitOnceComplete.
  4. Když InitOnceComplete vrátí, její návratová hodnota označuje, zda volající vlákno bylo úspěšné při inicializaci.
    • Pokud InitOnceComplete úspěšně, volající vlákno bylo úspěšné při inicializaci. Stav jednorázové inicializační struktury se změní na inicializaci a lpContext popisovač (pokud existuje) je uložen ve struktuře inicializace.
    • Pokud InitOnceComplete selže, bylo při inicializaci úspěšné další vlákno. Volající vlákno by mělo vyčistit všechna kontextová data, která vytvořila, a volat InitOnceBeginInitialize s INIT_ONCE_CHECK_ONLY načíst všechna kontextová data uložená v jednorázové inicializační struktuře.

Volání One-Time inicializace z více lokalit

Jednorázová inicializace chráněná jednou INIT_ONCE strukturou může být provedena z více lokalit; z každé lokality může být předáno jiné zpětné volání a synchronizace s zpětným voláním a bez zpětného volání může být smíšená. Inicializace je stále zaručená, že se úspěšně provede jen jednou.

Asynchronní a synchronní inicializace však nelze kombinovat: po pokusu o asynchronní inicializaci by pokusy o spuštění synchronní inicializace selhaly.

použití inicializace One-Time