Winapi 在GetOverlappedResultEx中使用超时来模拟超时等待?
使用获取重叠(即异步)i/O操作的结果时,可以要求GetOverlappdResult进行“等待”: 这是一个众所周知的问题 我想做的是使用Windows的异步功能来等待,但需要超时 我注意到,它有一个超时参数:Winapi 在GetOverlappedResultEx中使用超时来模拟超时等待?,winapi,overlapped-io,getoverlappedresult,Winapi,Overlapped Io,Getoverlappedresult,使用获取重叠(即异步)i/O操作的结果时,可以要求GetOverlappdResult进行“等待”: 这是一个众所周知的问题 我想做的是使用Windows的异步功能来等待,但需要超时 我注意到,它有一个超时参数: BOOL GetOverlappedResultEx( HANDLE hFile, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, DWORD dwMill
BOOL GetOverlappedResultEx(
HANDLE hFile,
LPOVERLAPPED lpOverlapped,
LPDWORD lpNumberOfBytesTransferred,
DWORD dwMilliseconds, <----------
BOOL bAlertable
);
除了对GetOverlappedResultEx的调用在5秒(5000毫秒)内没有返回之外。相反,存储子系统继续需要10-20分钟才能恢复故障
所以我随机尝试了一些东西
我看到另一个参数GetOverlappedResultsEx:
`bAlertable`
If this parameter is **TRUE** and the calling thread is in the waiting state, the function returns when the system queues an I/O completion routine or APC. The calling thread then runs the routine or function. Otherwise, the function does not return, and the completion routine or APC function is not executed.
A completion routine is queued when the [ReadFileEx][5] or [WriteFileEx][5] function in which it was specified has completed. The function returns and the completion routine is called only if *bAlertable* is **TRUE**, and the calling thread is the thread that initiated the read or write operation. An APC is queued when you call [QueueUserAPC][5].
这听起来不像我的处境:
- 我没有使用
ReadFileEx
- 我不是在呼叫
QueueUserAPC
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
//if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, False) //wait 5000 ms
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, True) //wait 5000 ms, alertable
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
DWORD le=ERROR\u SUCCESS//lastError=0
if(!ReadFile(FSourceDiskHandle,buffer,buffer\u SIZE,out bytesRead,overlapped)
{
//读取操作未同步完成。请查看是否仍挂起。
le=GetLastError;
如果(le==错误\u IO\u挂起)
{
le=错误\成功;
//如果(!GetOverlappedResult(FSourceDiskHandle,overlapped,out bytesRead,true)//
我是否可以模拟同步ReadFile
操作,但有一个超时,
使用GetOverlappedResultEx
是的,您可以,完全像您一样,并且已经尝试过了。这不是模拟。这将完全是同步文件读取。因为同步读取-这是异步读取+在I/O完成时原地等待。所以代码可以是下一个:
ULONG ReadFileTimeout(HANDLE hFile,
PVOID lpBuffer,
ULONG nNumberOfBytesToRead,
PULONG lpNumberOfBytesRead,
PLARGE_INTEGER ByteOffset,
ULONG dwMilliseconds)
{
OVERLAPPED ov;
ov.Offset = ByteOffset->LowPart;
ov.OffsetHigh = ByteOffset->HighPart;
ULONG dwError = NOERROR;
if (ov.hEvent = CreateEvent(0, 0, 0, 0))
{
dwError = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, &ov) ? NOERROR : GetLastError();
if (dwError == ERROR_IO_PENDING)
{
dwError = GetOverlappedResultEx(0/*yes, not need hFile*/,
&ov, lpNumberOfBytesRead, dwMilliseconds, FALSE) ? NOERROR : GetLastError();
}
CloseHandle(ov.hEvent);
}
else
{
dwError = GetLastError();
}
return dwError;
}
请注意,您必须(在异步文件的情况下)始终显式使用字节偏移量,从何处读取数据
GetOverlappedResultEx
通常执行下一步-检查OVERLAPPED
-I/O是否完成(只需将Internal
与STATUS\u PENDING
进行比较),如果没有完成(仍然Internal==STATUS\u PENDING
)您需要wait-it调用WaitForSingleObjectEx
,其中hEvent
来自重叠并传输dwms
,以及bAlertable
。如果hEvent
发出信号(wait\u OBJECT\u 0
从WaitForSingleObjectEx
返回)GetOverlappedResultEx
决定I/O完成并从OVERLAPPED
返回结果,否则返回相应的错误
但是,如果ReadFile
本身没有返回控制和等待-这里不可能执行某些操作。这意味着驱动程序开始在您的线程上等待。并且没有任何方法可以中断此驱动程序等待。看起来这正是您的情况。当您使用异步文件时-驱动程序不能等待,但是..有时(写得不好的驱动程序)这可以是WaitForSingleObject(overlapped.hEvent,5000)
?如果您愿意将自己限制在C++20,您可以使用一个协同程序来实现这一点。解释如何使用预构建的wait_for
函数。该实现基本上按照Jonathan Potter的建议执行。@JonathanPotter-但是GetOverlappedResultEx
和内部WaitForSingleObjectEx(overlapped.hEvent,dw毫秒,bAlertable)
除了调用GetOverlappedResultEx
不会在5秒钟(5000毫秒)内返回之外。相反,存储子系统继续需要10-20分钟才能返回故障。-这不可能。您在这里犯了一些错误GetOverlappedResultEx(FSourceDiskHandle,重叠,out bytesRead,5000,False)
将不迟于5秒后返回,如果您改为说它将持续10-20分钟-这是您调用中的100%错误GetOverlappedResultEx
-此api将仅等待来自重叠的事件,并且独立于文件。因此不能超过您的等待超时
`bAlertable`
If this parameter is **TRUE** and the calling thread is in the waiting state, the function returns when the system queues an I/O completion routine or APC. The calling thread then runs the routine or function. Otherwise, the function does not return, and the completion routine or APC function is not executed.
A completion routine is queued when the [ReadFileEx][5] or [WriteFileEx][5] function in which it was specified has completed. The function returns and the completion routine is called only if *bAlertable* is **TRUE**, and the calling thread is the thread that initiated the read or write operation. An APC is queued when you call [QueueUserAPC][5].
DWORD le = ERROR_SUCCESS; //lastError = 0
if (!ReadFile(FSourceDiskHandle, buffer, BUFFER_SIZE, out bytesRead, overlapped)
{
//The read operation did not complete synchronously. See if it's still pending.
le = GetLastError;
if (le == ERROR_IO_PENDING)
{
le = ERROR_SUCCESS;
//if (!GetOverlappedResult(FSourceDiskHandle, overlapped, out bytesRead, true) // <---bWait = true
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, False) //wait 5000 ms
if (!GetOverlappedResultEx(FSourceDiskHandle, overlapped, out bytesRead, 5000, True) //wait 5000 ms, alertable
le = GetLastError;
}
if (le != ERROR_SUCCESS)
LogFmt("Error reading source: %s (%d)', SysErrorMessage(le), le], TRACE_LEVEL_ERROR);
}
ULONG ReadFileTimeout(HANDLE hFile,
PVOID lpBuffer,
ULONG nNumberOfBytesToRead,
PULONG lpNumberOfBytesRead,
PLARGE_INTEGER ByteOffset,
ULONG dwMilliseconds)
{
OVERLAPPED ov;
ov.Offset = ByteOffset->LowPart;
ov.OffsetHigh = ByteOffset->HighPart;
ULONG dwError = NOERROR;
if (ov.hEvent = CreateEvent(0, 0, 0, 0))
{
dwError = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, &ov) ? NOERROR : GetLastError();
if (dwError == ERROR_IO_PENDING)
{
dwError = GetOverlappedResultEx(0/*yes, not need hFile*/,
&ov, lpNumberOfBytesRead, dwMilliseconds, FALSE) ? NOERROR : GetLastError();
}
CloseHandle(ov.hEvent);
}
else
{
dwError = GetLastError();
}
return dwError;
}