我正在使用异步过程调用(APC)使用ReadFileEx和WriteFileEx进行重叠的I / O请求。按照MSDN的定义,只有在定义APC的线程处于“可更改”状态时,这些函数的完成例程(APC)才会被处理。
here和there中的示例都使用SleepEx()函数通过执行SleepEx(INFINITE, TRUE)
来使线程保持警报状态,以便线程将无限地保持处于警报状态,直到所有APC都处于完成,这意味着线程将被挂起,直到所有APC完成。这不违反我们使用重叠I / O,ReadFileEx和WriteFileEx的原因吗?我认为整个想法是使线程响应并在后台耗时。请帮我解释一下这个想法。
尽管在第一个链接中提到我们可以使用SleepEx(0,TRUE)
使线程立即返回并可以同时处理APC,但我仍然不知道在APC之前的那段时间该怎么做返回以及如何知道何时返回。我的目标只是保持线程响应能力,而无所事事。
答案 0 :(得分:0)
不清楚您在这里要问什么,但我会对此一视同仁。
等待APC是否抵消了进行异步I / O的好处,这完全取决于您的设计。如果您写的是这样的话:
WriteFileEx(..., &overlapped, CompleteWrite);
SleepEx(INFINITE, TRUE);
那么显然,除了使程序过于复杂之外,您还没有完成任何事情。您也可以执行同步I / O。
但是您也可以编写类似的内容:
while (work_to_do)
{
DoSomeWork();
WriteFileEx(results);
SleepEx(0, TRUE);
}
现在,您避免了一些停机时间。如果WriteFileEx需要很长时间才能完成,则线程可以在此期间继续进行工作。
您还可以创建一个服务请求的线程。像这样:
DWORD ThreadProc(...)
{
while (!done)
{
SleepEx(INFINITE, TRUE);
}
}
该线程只是在等待有人使用QueueUserAPC
向其发送命令。如果此类线程发出了I / O,则它可能希望异步执行以允许它在等待I / O完成的同时处理其他命令。 (另一方面,为避免重新进入问题,可能不要这样做。)
我希望这能使您了解如何使用这些功能。但是请记住,这些都是非常的旧技术。如果有的话,您很少会在现代程序中使用它们。而是使用CreateThreadPoolIo
/ StartThreadPoolIo
之类的函数让Windows在您专用的工作线程上运行I / O完成。或者更好的方法是使用更高级别的面向任务的库,并避免这些低级的细节。
编辑-在主窗口线程上执行I / O
对此特定问题的简短答案是,不要这样做。在辅助线程上运行I / O,然后使用PostMessage
或SendMessage
将结果发送回主线程。如果由于某种原因您不能执行此操作,则必须使用修改后的消息循环。代替GetMessage
,而使用MsgWaitForMultipleObjects
,它将使您在等待I / O完成时处理窗口消息。
// error checking omitted
OVERLAPPED overlapped{};
ReadFile(file_handle, buffer, bytes_to_read, &bytes_read, &overlapped);
while (true)
{
DWORD wait_result = MsgWaitForMultipleObjects(
1,
&file_handle,
FALSE,
INFINITE,
QS_ALLINPUT);
if (wait_result = WAIT_OBJECT_0)
{
// I/O completed...
break;
}
}