首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将CancelSynchronousIo()放在WaitForSingleObject()上等待stdin?

如何将CancelSynchronousIo()放在WaitForSingleObject()上等待stdin?
EN

Stack Overflow用户
提问于 2017-11-16 18:28:40
回答 2查看 1.1K关注 0票数 1

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

WaitForSingleObject(https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85%29.aspx)`( GetStdHandle(STD_INPUT_HANDLE),.)

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

但是取消没有任何作用(返回0GetLastError()ERROR_NOT_FOUND)。

知道我可能做错什么了吗?

我应该可以取消这个等待stdin的新输入吗?

(实际上,我想对任何一个HANDLE ( GetFileType() )都这样做。

我发现了相关的讨论:

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

(背景:我正在尝试https://ghc.haskell.org/trac/ghc/ticket/8684。)

EN

Stack Overflow用户

发布于 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 (注意,在内部调用NtWaitForSingleObjectWaitForSingleObjectExSTATUS_ALERTED执行特殊检查),如果此状态--再次运行NtWaitForSingleObject --导致不能通过调用NtAlertThread破坏WaitForSingleObjectEx,但是NtWaitForSingleObject将被破坏。

因此,如果您需要中断等待std输入-创建额外的线程,它必须调用的不是CancelSynchronousIo (这是没有意义的)而是QueueUserAPCNtAlertThread (只有当您使用NtWaitForSingleObject。而输入线程必须在可报警状态下等待。因此,演示代码可以如下所示:

代码语言:javascript
运行
复制
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);
        }
    }
}
票数 3
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47336755

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档