【问题标题】:(MSDN)Make thread "alertable" constantly without blocking the thread(MSDN)使线程不断“警报”而不阻塞线程
【发布时间】:2018-12-14 07:10:13
【问题描述】:

我正在使用异步进程调用 (APC) 来执行使用 ReadFileEx 和 WriteFileEx 的重叠 I/O 请求。正如 MSDN 中所定义的,这些函数的完成例程(APC)只有在定义 APC 的线程处于“alertable”状态时才会被处理。

herethere 的例子都使用了SleepEx() 函数通过SleepEx(INFINITE, TRUE) 来保持线程的alertable 状态,这样线程就会无限保持alerable 状态直到所有的APCs 完成,这意味着线程暂停,直到所有 APC 完成。这不违反我们使用重叠 I/O、ReadFileEx 和 WriteFileEx 的原因吗?我认为整个想法是使线程响应并在后台花费时间。请帮我解释一下这个想法。

虽然在第一个链接中提到我们可以使用SleepEx(0,TRUE)使线程立即返回并且可以同时处理APC,但我仍然不知道在APC返回之前的这段时间内该怎么办如何知道他们什么时候回来。我的目标只是保持线程响应,但无事可做。

【问题讨论】:

  • 这不是处理异步 IO 完成的唯一方法。您可以使用 GetOverLappedResult 轮询 IO 的状态,并且可以使用 IO 完成端口来创建反应器/前摄器模式
  • “保持线程响应”是什么意思?线程是做什么的?它是如何分配工作项的?
  • 如果你的意思是 ui 线程 - 你需要使用 MsgWaitForMultipleObjectsExMWMO_ALERTABLE。有了这个你可以处理windows消息和apc
  • @DavidHaim 嗨,我想知道 GetOverlappedResult 在我使用带有完成例程的 Read/WriteFileEx 的情况下可以做什么?谢谢
  • @PeterRuderman 该线程必须在读取和写入文件的同时保持响应并更新进度条。

标签: multithreading asynchronous msdn overlapped-io


【解决方案1】:

不清楚你在这里问什么,但我会试一试。

等待 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 并使用 PostMessageSendMessage 将结果发送回主线程。如果由于某种原因您不能这样做,那么您必须使用修改后的消息循环。使用MsgWaitForMultipleObjects 代替GetMessage,这样您就可以在等待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;
  }
}

【讨论】:

  • 感谢您的回复。我目前使用的方式与您在“while(work_to_do)...”中使用的方式相同,这就是我提出问题的目的。当我们在主线程中放置一个while循环时,这同样会冻结主线程,这违反了我执行重叠io请求的目的。
  • 我知道你现在在追求什么。我会更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多