Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Драйвер, требующий отложенной обработки, может использовать рабочий элемент, содержащий указатель на подпрограмму обратного вызова драйвера, которая выполняет фактическую обработку. Драйвер помещает рабочий элемент в очередь, а системный рабочий поток удаляет рабочий элемент из очереди и запускает подпрограмму обратного вызова драйвера. Система поддерживает пул этих рабочих потоков системы, которые являются системными потоками, каждый из которых обрабатывает один рабочий элемент одновременно.
Драйвер связывает подпрограмму обратного вызова 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 выполнение всех потоков предотвращается. Кроме того, DPC, который работает на уровне IRQL = DISPATCH_LEVEL, не должен выполнять блокирующие вызовы. Однако системный рабочий поток, обрабатывающий рабочий элемент, выполняется в IRQL = PASSIVE_LEVEL. Таким образом, рабочий элемент может содержать блокирующие вызовы. Например, рабочий поток системы может ожидать объекта диспетчера.
Так как пул рабочих потоков системы является ограниченным ресурсом, подпрограммы WorkItem и WorkItemEx можно использовать только для операций, которые занимают короткий промежуток времени. Если одна из этих подпрограмм выполняется слишком долго (если она содержит неопределенный цикл, например) или ждет слишком долго, система может оказаться во взаимоблокировке. Таким образом, если драйверу требуется длительный период отложенной обработки, вместо этого следует вызвать PsCreateSystemThread для создания собственного системного потока.
Не вызывайте IoQueueWorkItem или IoQueueWorkItemEx, чтобы добавить в очередь элемент, который уже находится в ней. Это может привести к повреждению системных структур данных. Если драйвер помещает один и тот же рабочий элемент в очередь каждый раз при запуске определенной рутинной процедуры драйвера, можно использовать следующий метод, чтобы избежать повторного помещения рабочего элемента в очередь, если он уже там:
- Драйвер поддерживает список задач для рабочей подпрограммы.
- Этот список задач доступен в контексте, предоставленном рабочей подпрограмме. Рабочая подпрограмма и все подпрограммы драйверов, изменяющие список задач, синхронизируют доступ к списку.
- Каждый раз, когда выполняется рабочая процедура, она исполняет все задачи из списка и удаляет каждую задачу по мере её завершения.
- При поступлении новой задачи драйвер добавляет эту задачу в список. Драйвер помещает рабочий элемент в очередь только в том случае, если список задач был ранее пустым.
Рабочий поток системы удаляет рабочий элемент из очереди перед вызовом рабочего потока. Таким образом, поток драйвера может безопасно снова поставить рабочий элемент в очередь, как только рабочий поток начнет работу.