系統背景工作執行緒
需要延遲處理的驅動程式可以使用 工作專案,其中包含執行實際處理之驅動程式回呼常式的指標。 驅動程式會將工作專案排入佇列,而 系統背景工作執行緒 會從佇列中移除工作專案,並執行驅動程式的回呼常式。 系統會維護這些系統背景工作執行緒的集區,這些執行緒是一次處理一個工作專案的系統執行緒。
驅動程式會將 WorkItem 回呼常式與工作專案產生關聯。 當系統背景工作執行緒工作專案時,它會呼叫相關聯的 WorkItem 常式。 在 Windows Vista 和更新版本的 Windows 中,驅動程式可以改為將 WorkItemEx 常式與工作專案產生關聯。 WorkItemEx 會採用與 WorkItem 採用的參數不同的參數。
WorkItem 和 WorkItemEx 常式會在系統執行緒內容中執行。 如果驅動程式分派常式可以在使用者模式執行緒內容中執行,該常式可以呼叫 WorkItem 或 WorkItemEx 常式來執行任何需要系統執行緒內容的作業。
若要使用工作專案,驅動程式會執行下列步驟:
配置並初始化新的工作專案。
系統會使用 IO_WORKITEM 結構來保存工作專案。 若要配置新的 IO_WORKITEM 結構,並將其初始化為工作專案,驅動程式可以呼叫 IoAllocateWorkItem。 在 Windows Vista 和更新版本的 Windows 中,驅動程式也可以配置自己的 IO_WORKITEM 結構,並呼叫 IoInitializeWorkItem ,將結構初始化為工作專案。 (驅動程式應該呼叫 IoSizeofWorkItem ,以判斷保存工作專案所需的位元組數目。)
將回呼常式與工作專案建立關聯,並將工作專案排入佇列,以便系統背景工作執行緒。
若要將 WorkItem 常式與工作專案建立關聯,並將工作專案排入佇列,驅動程式應該呼叫 IoQueueWorkItem。 若要改為將 WorkItemEx 常式與工作專案建立關聯,並將工作專案排入佇列,驅動程式應該呼叫 IoQueueWorkItemEx。
不再需要工作專案之後,請釋放它。
IoAllocateWorkItem所配置的工作專案應該由IoFreeWorkItem釋出。 IoInitializeWorkItem初始化的工作專案必須先由IoUninitializeWorkItem取消初始化,才能釋放。
工作專案目前未排入佇列時,只能取消初始化或釋放工作專案。 系統在呼叫工作專案的回呼常式之前先清除佇列工作專案,因此可以從回呼內呼叫 IoFreeWorkItem 和 IoUninitializeWorkItem 。
需要起始需要冗長處理或進行封鎖呼叫之處理工作的 DPC,應該將該工作的處理委派給一或多個工作專案。 當 DPC 執行時,所有線程都無法執行。 此外,在 IRQL = DISPATCH_LEVEL執行的 DPC 不得進行封鎖呼叫。 不過,處理工作專案的系統背景工作執行緒會在 IRQL = PASSIVE_LEVEL執行。 因此,工作專案可以包含封鎖呼叫。 例如,系統背景工作執行緒可以在發送器物件上等候。
因為系統背景工作執行緒集區是有限的資源, 所以 WorkItem 和 WorkItemEx 常式只能用於需要短時間的作業。 如果其中一個常式執行太長, (如果包含無限迴圈,例如) 或等候太長,系統可能會死結。 因此,如果驅動程式需要長時間延遲處理,它應該改為呼叫 PsCreateSystemThread 來建立自己的系統執行緒。
請勿呼叫 IoQueueWorkItem 或 IoQueueWorkItemEx ,將已經在佇列中的工作專案排入佇列。 這樣做可能會導致系統資料結構損毀。 如果您的驅動程式每次執行特定驅動程式常式時都會將相同的工作專案排入佇列,您可以使用下列技術來避免第二次排入佇列工作專案:如果工作專案已經在佇列中:
- 驅動程式會維護背景工作常式的工作清單。
- 此工作清單可在提供給背景工作常式的內容中使用。 背景工作常式和任何修改工作清單的驅動程式常式,都會同步處理其清單的存取權。
- 每次背景工作常式執行時,都會執行清單中的所有工作,並在工作完成時從清單中移除每個工作。
- 當新工作送達時,驅動程式會將這項工作新增至清單中。 只有在工作清單先前是空的時,驅動程式才會將工作專案排入佇列。
系統背景工作執行緒會在呼叫背景工作執行緒之前,先從佇列中移除工作專案。 因此,驅動程式執行緒可以在背景工作執行緒開始執行時,安全地排入工作專案佇列。