在Windows 10上,我正在等待来自控制台的输入
WaitForSingleObject
( GetStdHandle(STD_INPUT_HANDLE), ... )
并使用CancelSynchronousIo()
取消此等待。
但是取消没有做任何事情(返回0
而GetLastError()
是ERROR_NOT_FOUND
)。
知道我可能做错了吗?
我是否可以取消此等待stdin上的新输入?
(我实际上希望对GetFileType()
为HANDLE
的任何FILE_TYPE_CHAR
执行此操作,不仅仅是stdin,而且stdin当然是最重要的用例,也是最简单的测试用法)
相关讨论我发现:
但不幸的是,他们只讨论ReadFile()
,而不是WaitForSingleObject()
。我也试过WaitForMultipleObjects()
(数组中只有一个对象),同样的问题。
(背景:我正试图improve input handling in the GHC Haskell compiler runtime。)
答案 0 :(得分:2)
CancelSynchronousIo
取消指定线程发出的I / O操作。更具体的是,它通过调用IRP
取消与指定线程关联的IoCancelIrp
个数据包。如果使用未记录的NtCancelSynchronousIoFile
(CancelSynchronousIo
在内部使用IoRequestToCancel = 0
调用它),我们可以更具选择性 - 仅取消使用指定IoRequestToCancel
的i / o请求(系统检查{{} 1}}并仅取消此请求)
但是Irp->UserIosb == IoRequestToCancel
这是不是I / O请求。此调用不会创建任何可以取消的WaitForSingleObject
。所以 - 没办法做到这一点。
但是,如果您将WaitForSingleObjectEx
设置为IRP
时使用QueueUserAPC
,则可以使用NtWaitForSingleObject
通过队列apc 中断等待到线程。如果使用WaitForSingleObjectEx
代替NtWaitForSingleObject
,我们也可以使用未记录的调用bAlertable
来提醒线程。在这种情况下,WaitForSingleObjectEx
将与TRUE
中断(请注意NtWaitForSingleObject
内部呼叫NtWaitForSingleObject
对NtAlertThread
进行特殊检查,如果此状态再次运行{ {3}} - 因此,我们无法通过调用STATUS_ALERTED
来解除WaitForSingleObjectEx
,但NtWaitForSingleObject
将被中断。
所以如果你需要休息等待std输入 - 创建额外的线程,它必须不是CancelSynchronousIo
(这是无意义的),而是QueueUserAPC
或STATUS_ALERTED
(仅当你使用{{3}时等待)。并且输入线程必须等待警报状态。所以演示代码看起来像:
NtAlertThread
答案 1 :(得分:1)
控制台I / O很难异步使用,它根本就不是为它而设计的。有关可能的解决方法,请参阅IO Completion Ports (IOCP) and Asynchronous I/O through STDIN, STDOUT and STDERR。
如果您不能选择,那么您必须:
在短暂超时的循环中使用WaitForSingleObject()
。创建一个标志变量,循环可以在每次迭代时查看,以便在设置标志时中断循环。
使用WaitForMutipleObjects()
,给它2 HANDLE
等待 - 一个用于控制台(或其他),一个用于来自CreateEvent()
的事件对象。然后,当您想要中断等待时,您可以使用SetEvent()
向该事件发出信号。 WaitForMutipleObjects()
的返回值会告诉您HANDLE
已发出信号。