Win32 事件 -- 我需要在清除事件时收到通知



Win 7, x64, Visual Studio Community 2015, C++

有一个线程需要暂停/取消暂停或终止,我目前使用手动重置"运行"或"杀死"事件。 线程中的循环每次暂停 5000 毫秒。

我的目标是能够在等待过程中停止等待或终止线程。

问题是我目前设置它的方式,当"run"事件进入非信号状态时,我需要收到通知,但是没有办法做到这一点,除非我创建一个极性倒置的事件,但这似乎是一个笨拙。 简而言之,我需要一个电平敏感信号,而不是边缘敏感信号。

也许事件应该只是切换运行状态?

这是线程函数:

DWORD WINAPI DAQ::_fakeOutFn(void *param) {
    DAQ *pThis = (DAQ *)param;
    const DWORD timeout = 5000;
    bool running = false;
    HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent };
    do {
        DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
        switch (result) {
        case WAIT_OBJECT_0: // Run started or continued
            running = true;
            pThis->outputIndex++;
            if (pThis->outputIndex >= pThis->numSamples)
                pThis->outputIndex = 0;
            // Wait here
            // Not sure how to cancel this if the TaskRunningEvent goes false during the wait
            DWORD result2 = WaitForMultipleObjects(2, handles, FALSE, timeout);
            // Check result2, and 'continue' the loop if hFakeTaskRunningEvent went to NON-SIGNALLED state
            break;
        case WAIT_OBJECT_0 + 1: // Kill requested
            running = false;
            break;
        default:
            _ASSERT_EXPR(FALSE, L"Wait error");
            break;
        }
    } while (running);
    return 0;
}

对正在运行和恢复状态使用单独的事件。 然后,您可以将恢复事件重置为暂停,并发出事件恢复的信号。 运行事件应该用于让线程知道它何时有工作要做,而不是何时应该暂停该工作一段时间。

DWORD WINAPI DAQ::_fakeOutFn(void *param)
{
    DAQ *pThis = (DAQ *)param;
    bool running = false;
    HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent };
    do
    {
        DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
        switch (result)
        {
            case WAIT_OBJECT_0: // Run started
            {
                running = true;
                pThis->outputIndex++;
                if (pThis->outputIndex >= pThis->numSamples)
                    pThis->outputIndex = 0;
                // check for pause here
                HANDLE handles2[] = { pThis->hFakeTaskResumeEvent, pThis->hFakeTaskKillEvent };
                DWORD result2 = WaitForMultipleObjects(2, handles2, FALSE, INFINITE);
                switch (result2)
                {
                    case WAIT_OBJECT_0;
                        break;
                    case WAIT_OBJECT_0 + 1: // Kill requested
                        running = false;
                        break;
                    default:
                        _ASSERT_EXPR(FALSE, L"Wait error");
                        break;
                }
                if (!running) break;
                // continue working...
                break;
            }
            case WAIT_OBJECT_0 + 1: // Kill requested
                running = false;
                break;
            default:
                _ASSERT_EXPR(FALSE, L"Wait error");
                break;
        }
    }
    while (running);
    return 0;
}

在这里我使用的不是事件,而是使用"命令"(运行,暂停,退出)将Apc队列到此线程。 但是需要了解有关任务的更多信息,以选择最佳解决方案。 你写服务?

struct DAQ 
{
    HANDLE _hEvent;
    enum STATE {
        running,
        paused,
        exit
    } _state;
    DAQ()
    {
        _hEvent = 0;
    }
    ~DAQ()
    {
        if (_hEvent)
        {
            ZwClose(_hEvent);
        }
    }
    NTSTATUS Init()
    {
        return ZwCreateEvent(&_hEvent, EVENT_ALL_ACCESS, 0, NotificationEvent, FALSE);
    }
    void Close()
    {
        if (HANDLE hEvent = InterlockedExchangePointer(&_hEvent, 0))
        {
            ZwClose(hEvent);
        }
    }
    DWORD fakeOutFn()
    {
        DbgPrint("runningn");
        _state = running;
        ZwSetEvent(_hEvent, 0);
        static LARGE_INTEGER Interval = { 0, MINLONG };
        do ; while (0 <= ZwDelayExecution(TRUE, &Interval) && _state != exit);
        DbgPrint("exitn");
        return 0;
    }
    static DWORD WINAPI _fakeOutFn(PVOID pThis)
    {
        return ((DAQ*)pThis)->fakeOutFn();
    }
    void OnApc(STATE state)
    {
        _state = state;
        static PCSTR stateName[] = { "running", "paused" };
        if (state < RTL_NUMBER_OF(stateName))
        {
            DbgPrint("%sn", stateName[state]);
        }
    }
    static void WINAPI _OnApc(PVOID pThis, PVOID state, PVOID)
    {
        ((DAQ*)pThis)->OnApc((STATE)(ULONG_PTR)state);
    }
};
void test()
{
    DAQ d;
    if (0 <= d.Init())
    {
        if (HANDLE hThread = CreateThread(0, 0, DAQ::_fakeOutFn, &d, 0, 0))
        {
            if (STATUS_SUCCESS == ZwWaitForSingleObject(d._hEvent, FALSE, 0))// need for not QueueApc too early. in case ServiceMain this event not need
            {
                d.Close();
                int n = 5;
                do 
                {
                    DAQ::STATE state;
                    if (--n)
                    {
                        state = (n & 1) != 0 ? DAQ::running : DAQ::paused;
                    }
                    else
                    {
                        state = DAQ::exit;
                    }
                    ZwQueueApcThread(hThread, DAQ::_OnApc, &d, (PVOID)state, 0);
                } while (n);
            }
            ZwWaitForSingleObject(hThread, FALSE, 0);
            ZwClose(hThread);
        }
    }
}

最新更新