Sdílet prostřednictvím


Systémová pracovní vlákna

Ovladač, který vyžaduje zpožděné zpracování, může použít pracovní položku, která obsahuje ukazatel na rutinu zpětného volání ovladače, která provádí skutečné zpracování. Ovladač zařadí pracovní položku do fronty a pracovní vlákno systému odebere pracovní položku z fronty a spustí rutinu zpětného volání ovladače. Systém udržuje fond těchto systémových pracovních vláken, což jsou systémová vlákna, která každý zpracovává jednu pracovní položku najednou.

Ovladač přidruží rutinu zpětného volání WorkItem k pracovní položce. Když pracovní vlákno systému zpracuje pracovní položku, volá přidruženou rutinu WorkItem . V systému Windows Vista a novějších verzích systému Windows může ovladač místo toho přidružit rutinu WorkItemEx k pracovní položce. WorkItemEx přebírá parametry, které se liší od parametrů, které WorkItem přebírá.

Rutiny WorkItem a WorkItemEx se spouští v kontextu systémového vlákna. Pokud se rutina odesílání ovladačů může spouštět v kontextu vlákna v režimu uživatele, může tato rutina volat rutinu WorkItem nebo WorkItemEx k provádění operací, které vyžadují kontext systémového vlákna.

Pokud chcete použít pracovní položku, ovladač provede následující kroky:

  1. Přidělení a inicializace nové pracovní položky

    Systém používá IO_WORKITEM strukturu k uložení pracovní položky. Pokud chcete přidělit novou strukturu IO_WORKITEM a inicializovat ji jako pracovní položku, může ovladač volat IoAllocateWorkItem. V systému Windows Vista a novějších verzích systému Windows může ovladač alternativně přidělit vlastní strukturu IO_WORKITEM a volat IoInitializeWorkItem k inicializaci struktury jako pracovní položky. (Ovladač by měl volat IoSizeofWorkItem k určení počtu bajtů, které jsou nezbytné k uložení pracovní položky.)

  2. Přidružte rutinu zpětného volání k pracovní položce a zařaďte pracovní položku do fronty tak, aby byla zpracována systémovým pracovním vláknem.

    Chcete-li přidružit rutinu WorkItem k pracovní položce a zařaďte pracovní položku do fronty, ovladač by měl volat IoQueueWorkItem. Chcete-li místo toho přiřadit rutinu WorkItemEx k pracovní položce a zařadit pracovní položku do fronty, ovladač by měl volat IoQueueWorkItemEx.

  3. Jakmile už pracovní položku nepotřebujete, uvolněte ji.

    Pracovní položka přidělená službou IoAllocateWorkItem by měla být uvolněna službou IoFreeWorkItem. Pracovní položka, která byla inicializována službou IoInitializeWorkItem , musí být před uvolněním neinicializována službou IoUninitializeWorkItem .

    Pracovní položka může být nenačtena nebo uvolněna pouze v době, kdy pracovní položka není aktuálně zařazena do fronty úkolů. Systém zruší frontu pracovní položky před voláním rutiny zpětného volání pracovní položky, takže IoFreeWorkItem a IoUninitializeWorkItem lze volat z zpětného volání.

DPC, který potřebuje zahájit úlohu zpracování, která vyžaduje zdlouhavé zpracování nebo která provádí blokující volání, by mělo delegovat zpracování tohoto úkolu na jednu nebo více pracovních položek. Při spuštění DPC jsou všechna vlákna bráněna v běhu. Kromě toho DPC, který běží na úrovni IRQL = DISPATCH_LEVEL, nesmí provádět blokující volání. Pracovní vlákno systému, které zpracovává pracovní položku, se však spouští v IRQL = PASSIVE_LEVEL. Pracovní položka proto může obsahovat blokující volání. Například systémové pracovní vlákno může čekat na objekt dispečera.

Vzhledem k tomu, že fond systémových pracovních vláken je omezený zdroj, lze rutiny WorkItem a WorkItemEx použít pouze pro operace, které zabírají krátkou dobu. Pokud jedna z těchto rutin běží příliš dlouho (pokud obsahuje například nekonečnou smyčku) nebo čeká příliš, systém se může dostat do stavu zablokování. Proto pokud ovladač vyžaduje dlouhá období zpožděného zpracování, měl by namísto toho zavolat funkci PsCreateSystemThread a vytvořit vlastní systémové vlákno.

Nevolejte IoQueueWorkItem nebo IoQueueWorkItemEx k zařazení pracovní položky do fronty, která již je ve frontě. To může způsobit poškození systémových datových struktur. Pokud ovladač zařadí stejnou pracovní položku do fronty při každém spuštění konkrétní rutiny ovladače, můžete použít následující techniku, abyste se vyhnuli řazení pracovní položky do fronty podruhé, pokud už je ve frontě:

  • Ovladač udržuje seznam úkolů pro rutinu pracovního procesu.
  • Tento seznam úkolů je k dispozici v kontextu zadaném rutině pracovního procesu. Rutina pracovního procesu a všechny rutiny ovladačů, které upravují seznam úkolů, synchronizují přístup k seznamu.
  • Pokaždé, když se pracovní rutina spustí, provede všechny úkoly v seznamu a při dokončení úkolu odebere každý úkol ze seznamu.
  • Když přijde nový úkol, ovladač přidá tento úkol do seznamu. Ovladač zařadí pracovní položku do fronty pouze v případě, že seznam úkolů byl dříve prázdný.

Pracovní vlákno systému odebere pracovní položku z fronty před voláním pracovního vlákna. Vlákno ovladače tak může pracovní položku bezpečně zařadit do fronty, jakmile se pracovní vlákno spustí.