시스템 작업자 스레드
지연된 처리가 필요한 드라이버는 실제 처리를 수행하는 드라이버 콜백 루틴에 대한 포인터가 포함된 작업 항목을 사용할 수 있습니다. 드라이버는 작업 항목을 큐에 대기시키고 시스템 작업자 스레드 는 큐에서 작업 항목을 제거하고 드라이버의 콜백 루틴을 실행합니다. 시스템은 각 작업 항목을 한 번에 하나씩 처리하는 시스템 스레드인 이러한 시스템 작업자 스레드의 풀을 유지 관리합니다.
드라이버는 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를 호출하여 큐에 이미 있는 작업 항목을 큐에 추가하지 마세요. 이렇게 하면 시스템 데이터 구조가 손상될 수 있습니다. 드라이버가 특정 드라이버 루틴을 실행할 때마다 동일한 작업 항목을 큐에 대기하는 경우 다음 기술을 사용하여 작업 항목을 큐에 이미 있는 경우 두 번째로 큐에 대기하지 않도록 할 수 있습니다.
- 드라이버는 작업자 루틴에 대한 작업 목록을 유지 관리합니다.
- 이 작업 목록은 작업자 루틴에 제공되는 컨텍스트에서 사용할 수 있습니다. 작업자 루틴 및 작업 목록을 수정하는 모든 드라이버 루틴은 목록에 대한 액세스를 동기화합니다.
- 작업자 루틴이 실행 될 때마다 목록의 모든 작업을 수행 하 고 작업이 완료 될 때 목록에서 각 작업을 제거 합니다.
- 새 작업이 도착하면 드라이버는 이 작업을 목록에 추가합니다. 드라이버는 작업 목록이 이전에 비어 있는 경우에만 작업 항목을 큐에 대기합니다.
시스템 작업자 스레드는 작업자 스레드를 호출하기 전에 큐에서 작업 항목을 제거합니다. 따라서 드라이버 스레드는 작업자 스레드가 실행되자마자 작업 항목을 다시 안전하게 큐에 대기할 수 있습니다.