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 initOnceBeginInitialize 或 InitOnceExecuteOnce 函式的 lpCon text 輸出參數中的呼叫端。
一次性初始化可以同步或異步執行。 選擇性回呼函式可用於同步一次性初始化。
同步一次性初始化
下列步驟描述不使用回呼函式的同步一次性初始化。
- 第一個呼叫 InitOnceBeginInitialize 函式的線程會成功啟動一次性初始化。 若要進行同步單次初始化,InitOnceBeginInitialize 必須呼叫,而不需 INIT_ONCE_ASYNC 旗標。
- 嘗試初始化的後續線程會遭到封鎖,直到第一個線程完成初始化或失敗為止。 如果第一個線程失敗,則允許下一個線程嘗試初始化,依序執行。
- 初始化完成時,線程會呼叫 InitOnceComplete 函式。 線程可以選擇性地建立同步處理物件(或其他內容數據),並在 InitOnceComplete 函式的 lpContext 參數中指定它。
- 如果初始化成功,一次性初始化結構的狀態會變更為初始化,而 lpContext 句柄(如果有的話)儲存在初始化結構中。 後續的初始化嘗試會傳回此內容數據。 如果初始化失敗,資料會 NULL。
下列步驟描述使用回呼函式的同步一次性初始化。
- 成功呼叫 InitOnceExecuteOnce 函式的第一個線程會將指標傳遞至應用程式定義的 InitOnceCallback 回調函式和回呼函式所需的任何數據。 如果呼叫成功,則會執行 InitOnceCallback 回呼函式。
- 嘗試初始化的後續線程會遭到封鎖,直到第一個線程完成初始化或失敗為止。 如果第一個線程失敗,則允許下一個線程嘗試初始化,依序執行。
- 初始化完成時,回呼函式會傳回。 回呼函式可以選擇性地建立同步處理物件(或其他內容數據),並在其 Context 輸出參數中指定它。
- 如果初始化成功,一次性初始化結構的狀態會變更為初始化,而 Context 句柄(如果有的話)會儲存在初始化結構中。 後續的初始化嘗試會傳回此內容數據。 如果初始化失敗,資料會 NULL。
異步一次性初始化
下列步驟描述異步的一次性初始化。
- 如果多個線程同時嘗試藉由呼叫 InitOnceBeginInitialize 搭配 INIT_ONCE_ASYNC來開始初始化,則函式會針對 所有線程成功,並將 fPending 參數設定為 TRUE。 初始化時實際上只有一個線程會成功;其他並行嘗試不會變更初始化狀態。
- 當 InitOnceBeginInitialize 傳回時,fPending 參數會指出初始化狀態:
- 如果 fPendingFALSE,則一個線程在初始化時成功。 其他線程應該清除他們建立的任何內容數據,並在 lpContextInitOnceBeginInitialize輸出參數中使用內容數據。
- 如果 fPendingTRUE,則初始化尚未完成,其他線程應該會繼續。
- 每個線程都會呼叫 InitOnceComplete 函式。 線程可以選擇性地建立同步處理物件(或其他內容數據),並在 InitOnceComplete的 lpContext 參數中指定它。
- 當 InitOnceComplete 傳回時,其傳回值會指出呼叫線程在初始化時是否成功。
- 如果 InitOnceComplete 成功,則呼叫線程已在初始化時成功。 一次性初始化結構的狀態會變更為初始化,lpContext 句柄(如果有的話)儲存在初始化結構中。
- 如果 InitOnceComplete 失敗,則另一個線程已在初始化時成功。 呼叫線程應該清除它已建立的任何內容數據,並呼叫 InitOnceBeginInitialize 搭配 INIT_ONCE_CHECK_ONLY 擷取儲存在一次性初始化結構中的任何內容數據。
從多個網站呼叫 One-Time 初始化
單一 INIT_ONCE 結構所保護的一次性初始化,可以從多個月台執行;不同的回呼可能會從每個網站傳遞,而且與 和 沒有回呼的同步處理可能會混合。 初始化仍保證只會成功執行一次。
不過,異步和同步初始化無法混合:一旦嘗試異步初始化,嘗試啟動同步初始化將會失敗。
相關主題