Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Un controlador que requiere procesamiento retrasado puede usar un elemento de trabajo, que contiene un puntero a una rutina de devolución de llamada del controlador que realiza el procesamiento real. El controlador coloca en cola el elemento de trabajo, y un subproceso de trabajo del sistema elimina el elemento de trabajo de la cola y ejecuta la rutina de callback del controlador. El sistema mantiene un grupo de estos subprocesos de trabajo del sistema, que son subprocesos del sistema que cada uno procesa un elemento de trabajo cada vez.
El controlador asocia una rutina de devolución de llamada WorkItem al elemento de trabajo. Cuando el subproceso de trabajo del sistema procesa el elemento de trabajo, llama a la rutina WorkItem asociada. En Windows Vista y versiones posteriores de Windows, un controlador puede asociar una rutina WorkItemEx con un elemento de trabajo. WorkItemEx toma parámetros diferentes de los parámetros que toma WorkItem .
Las rutinas WorkItem y WorkItemEx se ejecutan en un contexto de subproceso del sistema. Si una rutina de distribución de controladores se puede ejecutar en un contexto de subproceso en modo de usuario, esa rutina puede llamar a una rutina WorkItem o WorkItemEx para realizar cualquier operación que requiera un contexto de subproceso del sistema.
Para usar un elemento de trabajo, un controlador realiza los pasos siguientes:
Asigne e inicialice un nuevo elemento de trabajo.
El sistema usa una estructura IO_WORKITEM para contener un elemento de trabajo. Para asignar una nueva estructura IO_WORKITEM e inicializarla como un elemento de trabajo, el controlador puede llamar a IoAllocateWorkItem. En Windows Vista y versiones posteriores de Windows, el controlador puede asignar su propia estructura de IO_WORKITEM y llamar a IoInitializeWorkItem para inicializar la estructura como un elemento de trabajo. (El controlador debe llamar a IoSizeofWorkItem para determinar el número de bytes necesarios para contener un elemento de trabajo).
Asocie una rutina de devolución de llamada al elemento de trabajo y ponga en cola el elemento de trabajo para que lo procese un subproceso de trabajo del sistema.
Para asociar una rutina WorkItem con el elemento de trabajo y poner en cola el elemento de trabajo, el controlador debe llamar a IoQueueWorkItem. Para asociar en su lugar una rutina WorkItemEx con el elemento de trabajo y poner en cola el elemento de trabajo, el controlador debe llamar a IoQueueWorkItemEx.
Después de que el elemento de trabajo ya no sea necesario, libere el elemento.
IoFreeWorkItem debe liberar un elemento de trabajo asignado por IoAllocateWorkItem. Un elemento de trabajo inicializado por IoInitializeWorkItem debe no inicializarse mediante IoUninitializeWorkItem para poder liberarlo.
El elemento de trabajo solo puede estar sin inicializar o liberarse cuando no esté actualmente en cola. El sistema pone en cola el elemento de trabajo antes de llamar a la rutina de devolución de llamada del elemento de trabajo, por lo que IoFreeWorkItem y IoUninitializeWorkItem se pueden llamar desde dentro de la devolución de llamada.
Un DPC que necesita iniciar una tarea de procesamiento que requiera un procesamiento largo o que realice una llamada de bloqueo debe delegar el procesamiento de esa tarea en uno o varios elementos de trabajo. Mientras se ejecuta un DPC, se impide que se ejecuten todos los subprocesos. Además, un DPC, que se ejecuta en IRQL = DISPATCH_LEVEL, no debe realizar llamadas de bloqueo. Sin embargo, el subproceso de trabajo del sistema que procesa un elemento de trabajo se ejecuta en IRQL = PASSIVE_LEVEL. Por lo tanto, el elemento de trabajo puede contener llamadas de bloqueo. Por ejemplo, un subproceso de trabajo del sistema puede esperar a un objeto despachador.
Dado que el grupo de subprocesos de trabajo del sistema es un recurso limitado, las rutinas WorkItem y WorkItemEx solo se pueden usar para las operaciones que tardan un breve período de tiempo. Si una de estas rutinas se ejecuta durante demasiado tiempo (si contiene un bucle indefinido, por ejemplo) o espera demasiado tiempo, el sistema puede interbloquearse. Por lo tanto, si un controlador requiere largos períodos de procesamiento retrasado, debe llamar a PsCreateSystemThread para crear su propio subproceso del sistema.
No llame a IoQueueWorkItem ni IoQueueWorkItemEx para poner en cola un elemento de trabajo que ya está en la cola. Si lo hace, puede causar daños en las estructuras de datos del sistema. Si el controlador pone en cola el mismo elemento de trabajo cada vez que se ejecuta una rutina de controlador determinada, puede usar la siguiente técnica para evitar poner en cola el elemento de trabajo una segunda vez si ya está en la cola:
- El controlador mantiene una lista de tareas para la rutina de trabajo.
- Esta lista de tareas está disponible en el contexto que se proporciona a la rutina del trabajador. La rutina de trabajo y las rutinas de controlador que modifican la lista de tareas sincronizan su acceso a la lista.
- Cada vez que se ejecuta la rutina de trabajo, realiza todas las tareas de la lista y quita cada tarea de la lista a medida que se completa la tarea.
- Cuando llega una nueva tarea, el controlador agrega esta tarea a la lista. El controlador pone en cola el elemento de trabajo solo si la lista de tareas estaba vacía anteriormente.
El subproceso de trabajo del sistema quita el elemento de trabajo de la cola antes de llamar al subproceso de trabajo. Por lo tanto, un subproceso de controlador puede poner en cola el elemento de trabajo de nuevo en cuanto el subproceso de trabajo comienza a ejecutarse.