Inicialização One-Time
Os componentes geralmente são projetados para executar tarefas de inicialização quando são chamados pela primeira vez, em vez de quando são carregados. As funções de inicialização única garantem que essa inicialização ocorra apenas uma vez, mesmo quando vários threads podem tentar a inicialização.
Windows Server 2003 e Windows XP: Os aplicativos devem fornecer sua própria sincronização para inicialização única usando o funções interbloqueadas ou outro mecanismo de sincronização. As funções de inicialização única estão disponíveis a partir do Windows Vista e do Windows Server 2008.
As funções de inicialização única fornecem vantagens significativas para garantir que apenas um thread execute a inicialização:
- Eles são otimizados para velocidade.
- Eles criam as barreiras apropriadas nas arquiteturas de processador que os exigem.
- Eles suportam inicialização bloqueada e paralela.
- Eles evitam o bloqueio interno para que o código possa operar de forma assíncrona ou síncrona.
O sistema gerencia o processo de inicialização por meio de uma estrutura INIT_ONCE opaca que contém dados e informações de estado. O chamador aloca essa estrutura e a inicializa chamando InitOnceInitialize (para inicializar a estrutura dinamicamente) ou atribuindo a constante INIT_ONCE_STATIC_INIT à variável de estrutura (para inicializar a estrutura estaticamente). Inicialmente, os dados armazenados na estrutura de inicialização única são NULL e seu estado não é inicializado.
As estruturas de inicialização única não podem ser compartilhadas entre processos.
O thread que executa a inicialização pode, opcionalmente, definir um contexto que está disponível para o chamador após a conclusão da inicialização. O contexto pode ser um objeto de sincronização ou pode ser um valor ou uma estrutura de dados. Se o contexto for um valor, sua INIT_ONCE_CTX_RESERVED_BITS de ordem baixa deve ser zero. Se o contexto for uma estrutura de dados, a estrutura de dados deve ser DWORD-alinhada. O contexto é retornado ao chamador no parâmetro lpContext output da funçãoInitOnceBeginInitialize ouInitOnceExecuteOnce.
A inicialização única pode ser executada de forma síncrona ou assíncrona. Uma função de retorno de chamada opcional pode ser usada para inicialização única síncrona.
Inicialização única síncrona
As etapas a seguir descrevem a inicialização única síncrona que não usa uma função de retorno de chamada.
- O primeiro thread a chamar a funçãoInitOnceBeginInitialize com êxito faz com que a inicialização única seja iniciada. Para inicialização única síncrona, InitOnceBeginInitialize deve ser chamado sem o sinalizador INIT_ONCE_ASYNC.
- Os threads subsequentes que tentam a inicialização são bloqueados até que o primeiro thread conclua a inicialização ou falhe. Se o primeiro thread falhar, o próximo thread terá permissão para tentar a inicialização e assim por diante.
- Quando a inicialização é concluída, o thread chama o InitOnceComplete função. O thread pode, opcionalmente, criar um objeto de sincronização (ou outros dados de contexto) e especificá-lo no parâmetro lpContext da função InitOnceComplete.
- Se a inicialização for bem-sucedida, o estado da estrutura de inicialização única será alterado para inicializado e o identificador de lpContext (se houver) será armazenado na estrutura de inicialização. Tentativas de inicialização subsequentes retornam esses dados de contexto. Se a inicialização falhar, os dados serão NULL.
As etapas a seguir descrevem a inicialização única síncrona que usa uma função de retorno de chamada.
- O primeiro thread a chamar com êxito a funçãoInitOnceExecuteOnce dopassa um ponteiro para um definido pelo aplicativo InitOnceCallback função de retorno de chamada e quaisquer dados exigidos pela função de retorno de chamada. Se a chamada for bem-sucedida, a função de retorno de chamada InitOnceCallback será executada.
- Os threads subsequentes que tentam a inicialização são bloqueados até que o primeiro thread conclua a inicialização ou falhe. Se o primeiro thread falhar, o próximo thread terá permissão para tentar a inicialização e assim por diante.
- Quando a inicialização é concluída, a função de retorno de chamada retorna. A função de retorno de chamada pode, opcionalmente, criar um objeto de sincronização (ou outros dados de contexto) e especificá-lo em seu parâmetro Context output.
- Se a inicialização for bem-sucedida, o estado da estrutura de inicialização única será alterado para inicializado e o identificador de de contexto (se houver) será armazenado na estrutura de inicialização. Tentativas de inicialização subsequentes retornam esses dados de contexto. Se a inicialização falhar, os dados serão NULL.
Inicialização única assíncrona
As etapas a seguir descrevem a inicialização única assíncrona.
- Se vários threads simultaneamente tentarem iniciar a inicialização chamando InitOnceBeginInitialize com INIT_ONCE_ASYNC, a função terá êxito para todos os threads com o parâmetro fPending definido como TRUE. Apenas um thread será realmente bem-sucedido na inicialização; Outras tentativas simultâneas não alteram o estado de inicialização.
- Quando InitOnceBeginInitialize retorna, o parâmetro fPending indica o status de inicialização:
- Se fPending for FALSE, um thread foi bem-sucedido na inicialização. Outros threads devem limpar todos os dados de contexto que criaram e usar os dados de contexto no parâmetro de saída lpContext lpContext do InitOnceBeginInitialize.
- Se fPending estiver TRUE, a inicialização ainda não foi concluída e outros threads devem continuar.
- Cada thread chama a funçãoInitOnceComplete. O thread pode, opcionalmente, criar um objeto de sincronização (ou outros dados de contexto) e especificá-lo no parâmetro lpContext de InitOnceComplete.
- Quando InitOnceComplete retorna, seu valor de retorno indica se o thread de chamada foi bem-sucedido na inicialização.
- Se InitOnceComplete for bem-sucedido, o thread de chamada foi bem-sucedido na inicialização. O estado da estrutura de inicialização única é alterado para inicializado e o identificador de lpContext (se houver) é armazenado na estrutura de inicialização.
- Se InitOnceComplete falhar, outro thread foi bem-sucedido na inicialização. O thread de chamada deve limpar todos os dados de contexto que criou e chamar InitOnceBeginInitialize com INIT_ONCE_CHECK_ONLY para recuperar quaisquer dados de contexto armazenados na estrutura de inicialização única.
Chamando One-Time inicialização de vários sites
A inicialização única protegida por uma única estrutura INIT_ONCE pode ser realizada a partir de vários locais; Retorno de chamada diferente pode ser passado de cada site, e a sincronização com e sem retorno de chamada pode ser mista. A inicialização ainda é garantida para ser executada com êxito apenas uma vez.
No entanto, a inicialização assíncrona e síncrona não pode ser misturada: uma vez que a inicialização assíncrona é tentada, as tentativas de iniciar a inicialização síncrona falharão.
Tópicos relacionados
-
Usando One-Time de inicialização