DeviceIoControl超时后如何处理
在使用 DeviceIoControl
函数时,如果发生超时并且你希望手动中断或取消正在进行的 I/O 操作,可以通过以下几种方式来处理:
1. 使用 CancelIo
函数
CancelIo
是 Windows API 提供的一个函数,用于取消指定设备句柄的所有挂起的异步 I/O 操作。它只会影响异步操作(即 OVERLAPPED
模式下的 I/O 请求)。
使用方法:
BOOL result = CancelIo(hDevice);
if (!result) {
DWORD dwError = GetLastError();
// 处理错误
}
该函数会取消当前设备句柄上的所有未完成的异步 I/O 操作,包括 DeviceIoControl
请求。要注意:
- 取消操作后,相关的 I/O 操作将不会完成,
GetLastError()
会返回ERROR_OPERATION_ABORTED
。 CancelIo
只能取消未完成的 I/O 请求,已经完成的请求无法取消。
2. 使用 CancelIoEx
函数
CancelIoEx
是 CancelIo
的增强版本,它允许指定取消特定线程或设备句柄的 I/O 请求。它也适用于异步模式。
使用方法:
BOOL result = CancelIoEx(hDevice, NULL);
if (!result) {
DWORD dwError = GetLastError();
// 处理错误
}
CancelIoEx
允许通过指定 OVERLAPPED
结构来取消特定的异步 I/O 操作,或者传入 NULL
来取消所有挂起的操作。
3. 取消 OVERLAPPED
操作(异步模式)
如果你使用了 OVERLAPPED
结构,且正在等待某个异步 I/O 操作完成(例如使用 WaitForSingleObject
等等待 I/O 完成),你可以通过取消等待来停止操作。
// 假设使用 OVERLAPPED 和 WaitForSingleObject
DWORD dwWaitResult = WaitForSingleObject(overlapped.hEvent, timeoutMilliseconds);
if (dwWaitResult == WAIT_TIMEOUT) {
// 超时后取消 I/O 操作
CancelIo(hDevice); // 或者使用 CancelIoEx
}
在超时发生后,你可以使用 CancelIo
或 CancelIoEx
来取消正在进行的异步操作。
4. 异步 I/O 中的错误处理
如果你使用的是异步 I/O(OVERLAPPED
),当 DeviceIoControl
返回超时错误时,可以通过检查 GetLastError()
返回的错误代码来判断是否需要中断。
if (GetLastError() == ERROR_OPERATION_ABORTED) {
// 操作被中断,处理相关逻辑
}
5. 线程间通信中断
如果你在多线程环境中使用异步 I/O,且希望中断操作,可以通过线程间的信号机制(如 Event
、Mutex
、CriticalSection
等)来控制。你可以在某个线程中设置一个标志或事件,然后在等待 I/O 完成的线程中定期检查该标志,如果标志被设置,就提前退出或中断操作。
示例代码:取消异步 I/O 操作
#include <windows.h>
#include <iostream>
HANDLE hDevice;
OVERLAPPED overlapped = { 0 };
BOOL bResult;
// 超时后中断 I/O 操作
void CancelIoAfterTimeout()
{
// 假设你已经设置了一个等待事件
DWORD dwWaitResult = WaitForSingleObject(overlapped.hEvent, 5000); // 设置 5 秒超时
if (dwWaitResult == WAIT_TIMEOUT) {
std::cout << "I/O operation timed out, canceling...\n";
CancelIo(hDevice); // 取消所有异步 I/O 操作
// 或者使用 CancelIoEx(hDevice, &overlapped); 如果需要取消特定操作
} else {
std::cout << "I/O operation completed\n";
}
}
int main()
{
// 假设hDevice是已打开的设备句柄
hDevice = CreateFile(L"\\\\.\\Device\\MyDevice", GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to open device: " << GetLastError() << "\n";
return 1;
}
// 发起异步 I/O 操作
bResult = DeviceIoControl(hDevice, IOCTL_CODE, NULL, 0, NULL, 0, NULL, &overlapped);
if (!bResult) {
if (GetLastError() == ERROR_IO_PENDING) {
// 操作正在进行,等待超时
CancelIoAfterTimeout();
}
}
CloseHandle(hDevice);
return 0;
}
注意事项:
- 在取消操作后,通常需要检查设备的状态或驱动程序的返回值。取消操作后,可能会导致
DeviceIoControl
调用返回错误,例如ERROR_OPERATION_ABORTED
。 - 如果你不使用异步 I/O(即没有
OVERLAPPED
结构),则无法直接取消操作。在这种情况下,你可能需要使用线程或进程间的控制机制来中断操作。
希望这些方法能帮助你处理中断超时的 I/O 操作!