如何在WaitForSingleObject()上等待stdin上取消同步Io()?

时间:2017-11-16 18:28:41

标签: windows winapi windows-console

在Windows 10上,我正在等待来自控制台的输入

WaitForSingleObject ( GetStdHandle(STD_INPUT_HANDLE), ... )

并使用CancelSynchronousIo()取消此等待。

但是取消没有做任何事情(返回0GetLastError()ERROR_NOT_FOUND)。

知道我可能做错了吗?
我是否可以取消此等待stdin上的新输入?

(我实际上希望对GetFileType()HANDLE的任何FILE_TYPE_CHAR执行此操作,不仅仅是stdin,而且stdin当然是最重要的用例,也是最简单的测试用法)

相关讨论我发现:

但不幸的是,他们只讨论ReadFile(),而不是WaitForSingleObject()。我也试过WaitForMultipleObjects()(数组中只有一个对象),同样的问题。

背景:我正试图improve input handling in the GHC Haskell compiler runtime

2 个答案:

答案 0 :(得分:2)

CancelSynchronousIo取消指定线程发出的I / O操作。更具体的是,它通过调用IRP取消与指定线程关联的IoCancelIrp个数据包。如果使用未记录的NtCancelSynchronousIoFileCancelSynchronousIo在内部使用IoRequestToCancel = 0调用它),我们可以更具选择性 - 仅取消使用指定IoRequestToCancel的i / o请求(系统检查{{} 1}}并仅取消此请求)

但是Irp->UserIosb == IoRequestToCancel这是不是I / O请求。此调用不会创建任何可以取消的WaitForSingleObject。所以 - 没办法做到这一点。

但是,如果您将WaitForSingleObjectEx设置为IRP时使用QueueUserAPC,则可以使用NtWaitForSingleObject通过队列apc 中断等待到线程。如果使用WaitForSingleObjectEx代替NtWaitForSingleObject,我们也可以使用未记录的调用bAlertable来提醒线程。在这种情况下,WaitForSingleObjectEx将与TRUE中断(请注意NtWaitForSingleObject内部呼叫NtWaitForSingleObjectNtAlertThread进行特殊检查,如果此状态再次运行{ {3}} - 因此,我们无法通过调用STATUS_ALERTED来解除WaitForSingleObjectEx,但NtWaitForSingleObject将被中断。

所以如果你需要休息等待std输入 - 创建额外的线程,它必须不是CancelSynchronousIo(这是无意义的),而是QueueUserAPCSTATUS_ALERTED(仅当你使用{{3}时等待)。并且输入线程必须等待警报状态。所以演示代码看起来像:

NtAlertThread

答案 1 :(得分:1)

控制台I / O很难异步使用,它根本就不是为它而设计的。有关可能的解决方法,请参阅IO Completion Ports (IOCP) and Asynchronous I/O through STDIN, STDOUT and STDERR

如果您不能选择,那么您必须:

  1. 在短暂超时的循环中使用WaitForSingleObject()。创建一个标志变量,循环可以在每次迭代时查看,以便在设置标志时中断循环。

  2. 使用WaitForMutipleObjects(),给它2 HANDLE等待 - 一个用于控制台(或其他),一个用于来自CreateEvent()的事件对象。然后,当您想要中断等待时,您可以使用SetEvent()向该事件发出信号。 WaitForMutipleObjects()的返回值会告诉您HANDLE已发出信号。