ReadFile、WriteFile、DeviceIoControl等函数的OVERLAPPED*参数为NULL时为同步I/O,此时这些函数的内部会创建一个事件对象并等待该对象,当驱动程序完成I/O时,会调用IoCompleteRequest设置该事件对象,于是ReadFile、WriteFile、DeviceIoControl就返回。注意IRP_MJ_READ/WRITE、IRP_MJ_DEVICE_CONTROL等派遣函数返回不代表ReadFile、WriteFile、DeviceIoControl就返回,当执行同步I/O时,驱动程序只有在调用IoCompleteRequest后,ReadFile、WriteFile、DeviceIoControl才会返回。应用程序通过多线程对同一个设备句柄执行同步I/O时,驱动程序通过StartIO来串行化IRP,IRP_MJ_READ/WRITE、IRP_MJ_DEVICE_CONTROL派遣函数中首先将代表应用程序请求的IRP标记为挂起(PENDING),然后通过IoStartPacket函数将该IRP插入系统维护的队列中,最后返回STATUS_PENDING;而在StartIO中会执行IoCompleteRequest,同步方式的ReadFile、WriteFile、DeviceIoControl就返回。
应用程序同步I/O与异步I/O的差异仅在于事件内核对象,同步I/O时,事件内核对象由ReadFile、WriteFile、DeviceIoControl函数内部创建;异步I/O时,由用户创建并传入到ReadFile、WriteFile、DeviceIoControl这些函数的最后一个参数中。
驱动程序中,且不论READ/WRITE_REGISTER_XXX、READ/WRITE_PORT_XXX这些函数是否可以并行执行,从逻辑角度考虑,多个线程同时发起IRP时,应遵循先到先服务原则,所以,一个完善的驱动程序应使用StartIO来串行化IRP。