共用方式為


One-Time 初始化

元件通常會設計為在第一次呼叫時執行初始化工作,而不是載入它們時。 一次性初始化函式可確保此初始化只會發生一次,即使多個線程可能嘗試初始化也一次。

Windows Server 2003 和 Windows XP: 應用程式必須使用 聯結函式 或其他同步處理機制,提供自己的一次性初始化同步處理。 從 Windows Vista 和 Windows Server 2008 開始,即可使用一次性初始化函式。

一次性初始化函式提供顯著優勢,以確保只有一個線程執行初始化:

  • 它們已針對速度進行優化。
  • 它們會在需要它們的處理器架構上建立適當的障礙。
  • 它們同時支援鎖定和平行初始化。
  • 它們可避免內部鎖定,讓程式代碼可以異步或同步作。

系統會透過包含數據和狀態資訊的不透明 INIT_ONCE 結構來管理初始化程式。 呼叫端會配置這個結構,並藉由呼叫 InitOnceInitialize 來初始化它(以動態方式初始化結構),或將常數 INIT_ONCE_STATIC_INIT 指派給結構變數(以靜態方式初始化結構)。 一開始,儲存在一次性初始化結構中的數據為 NULL,且其狀態未初始化。

單次初始化結構無法跨進程共用。

執行初始化的線程可以選擇性地設定初始化完成後,呼叫端可以使用的內容。 內容可以是同步處理物件,也可以是值或數據結構。 如果內容是值,則其低階 INIT_ONCE_CTX_RESERVED_BITS 必須是零。 如果內容是數據結構,則數據結構必須 DWORD對齊。 內容會傳回給 initOnceBeginInitialize initOnceBeginInitializeInitOnceExecuteOnce 函式的 lpCon text 輸出參數中的呼叫端。

一次性初始化可以同步或異步執行。 選擇性回呼函式可用於同步一次性初始化。

同步一次性初始化

下列步驟描述不使用回呼函式的同步一次性初始化。

  1. 第一個呼叫 InitOnceBeginInitialize 函式的線程會成功啟動一次性初始化。 若要進行同步單次初始化,InitOnceBeginInitialize 必須呼叫,而不需 INIT_ONCE_ASYNC 旗標。
  2. 嘗試初始化的後續線程會遭到封鎖,直到第一個線程完成初始化或失敗為止。 如果第一個線程失敗,則允許下一個線程嘗試初始化,依序執行。
  3. 初始化完成時,線程會呼叫 InitOnceComplete 函式。 線程可以選擇性地建立同步處理物件(或其他內容數據),並在 InitOnceComplete 函式的 lpContext 參數中指定它。
  4. 如果初始化成功,一次性初始化結構的狀態會變更為初始化,而 lpContext 句柄(如果有的話)儲存在初始化結構中。 後續的初始化嘗試會傳回此內容數據。 如果初始化失敗,資料會 NULL

下列步驟描述使用回呼函式的同步一次性初始化。

  1. 成功呼叫 InitOnceExecuteOnce 函式的第一個線程會將指標傳遞至應用程式定義的 InitOnceCallback 回調函式和回呼函式所需的任何數據。 如果呼叫成功,則會執行 InitOnceCallback 回呼函式。
  2. 嘗試初始化的後續線程會遭到封鎖,直到第一個線程完成初始化或失敗為止。 如果第一個線程失敗,則允許下一個線程嘗試初始化,依序執行。
  3. 初始化完成時,回呼函式會傳回。 回呼函式可以選擇性地建立同步處理物件(或其他內容數據),並在其 Context 輸出參數中指定它。
  4. 如果初始化成功,一次性初始化結構的狀態會變更為初始化,而 Context 句柄(如果有的話)會儲存在初始化結構中。 後續的初始化嘗試會傳回此內容數據。 如果初始化失敗,資料會 NULL

異步一次性初始化

下列步驟描述異步的一次性初始化。

  1. 如果多個線程同時嘗試藉由呼叫 InitOnceBeginInitialize 搭配 INIT_ONCE_ASYNC來開始初始化,則函式會針對 所有線程成功,並將 fPending 參數設定為 TRUE。 初始化時實際上只有一個線程會成功;其他並行嘗試不會變更初始化狀態。
  2. InitOnceBeginInitialize 傳回時,fPending 參數會指出初始化狀態:
    • 如果 fPendingFALSE,則一個線程在初始化時成功。 其他線程應該清除他們建立的任何內容數據,並在 lpContextInitOnceBeginInitialize輸出參數中使用內容數據。
    • 如果 fPendingTRUE,則初始化尚未完成,其他線程應該會繼續。
  3. 每個線程都會呼叫 InitOnceComplete 函式。 線程可以選擇性地建立同步處理物件(或其他內容數據),並在 InitOnceCompletelpContext 參數中指定它。
  4. InitOnceComplete 傳回時,其傳回值會指出呼叫線程在初始化時是否成功。
    • 如果 InitOnceComplete 成功,則呼叫線程已在初始化時成功。 一次性初始化結構的狀態會變更為初始化,lpContext 句柄(如果有的話)儲存在初始化結構中。
    • 如果 InitOnceComplete 失敗,則另一個線程已在初始化時成功。 呼叫線程應該清除它已建立的任何內容數據,並呼叫 InitOnceBeginInitialize 搭配 INIT_ONCE_CHECK_ONLY 擷取儲存在一次性初始化結構中的任何內容數據。

從多個網站呼叫 One-Time 初始化

單一 INIT_ONCE 結構所保護的一次性初始化,可以從多個月台執行;不同的回呼可能會從每個網站傳遞,而且與 和 沒有回呼的同步處理可能會混合。 初始化仍保證只會成功執行一次。

不過,異步和同步初始化無法混合:一旦嘗試異步初始化,嘗試啟動同步初始化將會失敗。

使用 One-Time 初始化