需要延遲處理的驅動程式可以使用 工作專案,其中包含執行實際處理之驅動程式回呼常式的指標。 驅動程式會將工作專案排入佇列, 而系統背景工作執行緒 會從佇列中移除工作專案,並執行驅動程式的回呼常式。 系統會維護這些系統工作執行緒的集區,每個執行緒一次處理一個工作項目。
驅動程式會將 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 來將佇列中已有的工作專案排入佇列。 這樣做可能會導致系統資料結構損毀。 如果您的驅動程式每次執行特定驅動程式常式時都會將相同的工作專案排入佇列,您可以使用下列技術來避免在工作專案已在佇列中時再次排入佇列:
- 驅動程式會維護工作程序的工作清單。
- 此作業清單可在提供給工作者常式的內容中使用。 工作常式及任何修改工作清單的驅動程式常式都會進行清單存取的同步。
- 每次工作者程序執行時,它都會執行清單中的所有任務,並在任務完成後從清單中移除該任務。
- 當新任務到達時,驅動程式會將此任務新增至清單。 只有在工作清單先前是空的時,驅動程式才會將工作專案排入佇列。
系統工作執行緒會在呼叫工作執行緒之前,先從佇列中移除工作專案。 因此,驅動程式執行緒可以在工作執行緒開始執行時,安全地再次將工作項目排入佇列。