Mutex 物件的簡介

如其名所示,Mutex 物件是一種同步處理機制,其設計目的是確保對一組核心模式執行緒之間共用的單一資源互斥存取。 只有使用執行背景工作執行緒的高階驅動程式,例如檔案系統驅動程式 (FSD) ,可能會使用 mutex 物件。

可能的話,具有驅動程式建立執行緒或背景工作執行緒回呼常式的高階驅動程式可能會使用 mutex 物件。 不過,任何具有可分頁執行緒或背景工作執行緒回呼常式的驅動程式都必須非常小心地管理其 mutex 物件的取得、等候和釋放。

Mutex 物件具有內建功能,僅提供系統 (核心模式,) 執行緒互斥、無鎖死存取 SMP 機器中的共用資源。 核心會一次將 Mutex 的擁有權指派給單一線程。

取得 mutex 的擁有權可防止傳遞一般核心模式非同步程序呼叫, (APCs) 。 除非核心發出APC_LEVEL軟體插斷來執行特殊核心 APC,例如 I/O 管理員的 IRP 完成常式,以將結果傳回給 I/O 作業的原始要求者,否則 APC 不會先占執行緒

執行緒可以取得 mutex 物件的擁有權,該物件已經擁有 (遞迴擁有權) ,但線上程完全釋放擁有權之前,遞迴取得的 mutex 物件不會設定為 Signaled 狀態。 這類執行緒必須明確釋放 Mutex,因為它取得擁有權的次數,才能讓另一個執行緒取得 mutex。

核心永遠不會允許擁有 Mutex 的執行緒造成轉換至使用者模式,而不需要先釋放 Mutex 並將它設定為 Signaled 狀態。 如果擁有 mutex 的任何 FSD 建立或驅動程式建立執行緒嘗試在釋放 mutex 的擁有權之前,先將控制權傳回 I/O 管理員,核心就會關閉系統。

任何使用 mutex 物件的驅動程式都必須呼叫 KeInitializeMutex 一次,才能等候或釋放其 mutex 物件。 下圖說明兩個系統執行緒如何使用 mutex 物件。

說明正在等候 mutex 物件的圖表。

如上圖所示,使用 mutex 物件的驅動程式必須提供 mutex 物件的儲存空間,該物件必須駐留。 驅動程式可以使用驅動程式所建立 裝置物件的裝置延伸 模組、控制器擴充功能,如果使用 控制器物件,或是驅動程式所配置的非分頁集區。

當驅動程式呼叫 KeInitializeMutex (通常是從其 AddDevice 常式) 時,它必須將指標傳遞給 mutex 物件的驅動程式儲存體,核心會初始化為 Signaled 狀態。

在這類高階驅動程式初始化之後,它可以管理共用資源的互斥存取權,如上圖所示。 例如,驅動程式的分派常式原本是同步作業,而執行緒可能會使用 mutex 來保護為 IRP 建立的驅動程式佇列。

因為 KeInitializeMutex一律會將 mutex 物件的初始狀態設定為 Signaled (,如上圖所示) :

  1. 分派常式的初始呼叫 KeWaitForSingleObjectMutex 指標會將目前的執行緒立即放入就緒狀態、提供 mutex 的執行緒擁有權,並將 mutex 狀態重設為 Not-Signaled。 一旦分派常式繼續執行,就可以安全地將 IRP 插入受 mutex 保護的佇列中。

  2. 當第二個執行緒 (另一個分派常式、驅動程式提供的背景工作執行緒回呼常式,或驅動程式建立的執行緒) 使用Mutex指標呼叫KeWaitForSingleObject時,第二個執行緒會進入等候狀態。

  3. 當分派常式依照步驟 1 所述完成佇列 IRP 時,它會使用Mutex指標和 Boolean Wait值呼叫KeReleaseMutex,指出它是否要呼叫KeWaitForSingleObject (或KeWaitForMutexObject) ,並在KeReleaseMutex傳回控制項時立即呼叫Mutex

  4. 假設分派常式在步驟 3 (Wait 設定為 FALSE) 釋出 mutex 的擁有權,Mutex 會設定為 KeReleaseMutex的 Signaled 狀態。 mutex 目前沒有擁有者,因此核心會判斷另一個執行緒是否正在等候該 Mutex。 如果是,核心會使第二個執行緒 (看到步驟 2) mutex 擁有者,可能會將執行緒的優先權提升為最低即時優先順序值,並將其狀態變更為就緒。

  5. 核心會在處理器可用時立即分派執行的第二個執行緒:也就是說,當沒有其他優先順序較高的執行緒處於就緒狀態,而且沒有核心模式常式可在較高的 IRQL 執行時。 第二個執行緒 (分派常式佇列 IRP 或驅動程式的背景工作執行緒回呼常式,或驅動程式建立的執行緒取消佇列 IRP) 現在可以安全地存取受 mutex 保護的 IRP 佇列,直到呼叫 KeReleaseMutex為止。

如果執行緒以遞迴方式取得 Mutex 物件的擁有權,該執行緒必須明確呼叫 KeReleaseMutex ,因為它在 Mutex 上等候的次數,才能將 mutex 物件設定為 Signaled 狀態。 例如,如果執行緒呼叫KeWaitForSingleObject,然後使用相同的Mutex指標來呼叫 KeWaitForMutexObject,則必須在取得 mutex 時呼叫KeReleaseMutex兩次,才能將該 Mutex 物件設定為 Signaled 狀態。

呼叫KeReleaseMutex並將Wait參數設定為TRUE表示呼叫端在從KeReleaseMutex傳回時立即呼叫KeWaitXxx支援常式的意圖。

請考慮下列指導方針,將 Wait 參數設定為 KeReleaseMutex:

在 IRQL PASSIVE_LEVEL上執行的可分頁執行緒或可分頁驅動程式常式,不應呼叫 KeReleaseMutex並將 Wait 參數設定為 TRUE。 如果呼叫端在 呼叫 KeReleaseMutexKeWaitXxx物件 () 之間呼叫,就會造成嚴重分頁錯誤。

任何在 IRQL 上執行且大於 PASSIVE_LEVEL 的標準驅動程式常式,都無法等候任何發送器物件的非零間隔,而不需要關閉系統。 不過,如果這類常式在 IRQL 上執行時擁有 mutex 小於或等於DISPATCH_LEVEL,這類常式可以呼叫 KeReleaseMutex

如需標準驅動程式常式執行之 IRQL 的摘要,請參閱 管理硬體優先順序