在Windows 10上,我正在等待来自控制台的输入
WaitForSingleObject
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85%29.aspx)`( GetStdHandle(STD_INPUT_HANDLE),.)
并使用CancelSynchronousIo()
取消此等待。
但是取消没有任何作用(返回0
,GetLastError()
是ERROR_NOT_FOUND
)。
知道我可能做错什么了吗?
我应该可以取消这个等待stdin的新输入吗?
(实际上,我想对任何一个HANDLE
( GetFileType()
)都这样做。
我发现了相关的讨论:
但不幸的是,他们只讨论ReadFile()
,而不是WaitForSingleObject()
。我也尝试过WaitForMultipleObjects()
(数组中只有一个对象),同样的问题。
(背景:我正在尝试https://ghc.haskell.org/trac/ghc/ticket/8684。)
发布于 2017-11-16 22:55:02
CancelSynchronousIo
取消由指定线程发出的I/O操作。更具体的是,它通过调用IRP
取消与指定线程关联的IoCancelIrp
数据包。如果使用无文档化的NtCancelSynchronousIoFile
(CancelSynchronousIo
内部调用IoRequestToCancel = 0
),我们可以进行更多的选择--只取消使用指定IoRequestToCancel
的i/o请求(系统检查Irp->UserIosb == IoRequestToCancel
,而只取消此请求)。
但是WaitForSingleObject
,这是,而不是I/O请求。此调用不创建任何可以取消的IRP
。所以-不可能这么做。
但是,如果您使用WaitForSingleObjectEx
,并将bAlertable
设置为TRUE
-您可以通过中断、等待、、队列、apc和使用QueueUserAPC
来执行线程。另外,如果使用NtWaitForSingleObject
而不是WaitForSingleObjectEx
,我们也可以使用无文档化的调用NtAlertThread
来警告线程。在这种情况下,NtWaitForSingleObject
将与STATUS_ALERTED
(注意,在内部调用NtWaitForSingleObject
的WaitForSingleObjectEx
为STATUS_ALERTED
执行特殊检查),如果此状态--再次运行NtWaitForSingleObject
--导致不能通过调用NtAlertThread
破坏WaitForSingleObjectEx
,但是NtWaitForSingleObject
将被破坏。
因此,如果您需要中断等待std输入-创建额外的线程,它必须调用的不是CancelSynchronousIo
(这是没有意义的)而是QueueUserAPC
或NtAlertThread
(只有当您使用NtWaitForSingleObject
。而输入线程必须在可报警状态下等待。因此,演示代码可以如下所示:
extern "C" NTSYSCALLAPI NTSTATUS NTAPI NtAlertThread(HANDLE ThreadHandle);
VOID NTAPI OnApc(ULONG_PTR Parameter)
{
DbgPrint("OnApc(%p)\n", Parameter);
}
DWORD CALLBACK BreakWaitThread(HANDLE hThread)
{
switch (LONG status = MessageBoxW(0, L"Use Apc(yes) or Alert(No) ?", L"BreakWaitThread",
MB_ICONQUESTION|MB_YESNOCANCEL|MB_DEFBUTTON3))
{
case IDYES:
if (!QueueUserAPC(OnApc, hThread, 0))
{
DbgPrint("QueueUserAPC=%u\n", GetLastError());
}
break;
case IDNO:
if (0 > (status = NtAlertThread(hThread)))
{
DbgPrint("AlertThread=%x\n", status);
}
break;
case IDCANCEL:
DbgPrint("canceled\n");
break;
default:
DbgPrint("MessageBox=%x\n", status);
}
CloseHandle(hThread);
return 0;
}
void ConsoleLoop(HANDLE hStdIn)
{
ULONG NumberOfEvents, NumberOfEventsRead, n;
INPUT_RECORD buf[8], *p;
for (;;)
{
switch (ZwWaitForSingleObject(hStdIn, TRUE, 0))
//switch (WaitForSingleObjectEx(hStdIn, INFINITE, TRUE))
{
case WAIT_OBJECT_0:
while (GetNumberOfConsoleInputEvents(hStdIn, &NumberOfEvents) && NumberOfEvents)
{
do
{
NumberOfEventsRead = min(RTL_NUMBER_OF(buf), NumberOfEvents);
if (ReadConsoleInput(hStdIn, buf, NumberOfEventsRead, &NumberOfEventsRead) && NumberOfEventsRead)
{
n = NumberOfEventsRead;
p = buf;
do
{
if (p->EventType == KEY_EVENT)
{
DbgPrint("%u(%u) %C %x %x %x\n",
p->Event.KeyEvent.bKeyDown,
p->Event.KeyEvent.wRepeatCount,
p->Event.KeyEvent.uChar.UnicodeChar,
p->Event.KeyEvent.wVirtualKeyCode,
p->Event.KeyEvent.wVirtualScanCode,
p->Event.KeyEvent.dwControlKeyState);
if (VK_OEM_PERIOD == p->Event.KeyEvent.wVirtualKeyCode)
{
return ;//if user type '.' return for demo
}
}
} while (p++, --n);
}
else
{
FlushConsoleInputBuffer(hStdIn);
break;
}
} while (NumberOfEvents -= NumberOfEventsRead);
}
continue;
case STATUS_USER_APC:
DbgPrint("\nUSER_APC\n");
return;
case STATUS_ALERTED:
DbgPrint("\nALERTED\n");
return;
case WAIT_FAILED :
DbgPrint("\nWAIT_FAILED=%u\n", GetLastError());
return;
default:
__debugbreak();
return;
}
}
}
void SimpleDemo()
{
if (HANDLE hCurrentThread = OpenThread(THREAD_ALERT|THREAD_SET_CONTEXT , FALSE, GetCurrentThreadId()))
{
ULONG dwThreadId;
HANDLE hThread = CreateThread(0, 0, BreakWaitThread, hCurrentThread, 0, &dwThreadId);
if (hThread)
{
ConsoleLoop(GetStdHandle(STD_INPUT_HANDLE));
PostThreadMessage(dwThreadId, WM_QUIT, 0, 0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
else
{
CloseHandle(hCurrentThread);
}
}
}
https://stackoverflow.com/questions/47336755
复制相似问题