【问题标题】:What happens when a message is triggered before the previously dispatched message callback is complete?在之前发送的消息回调完成之前触发消息会发生什么?
【发布时间】:2012-09-24 19:21:55
【问题描述】:

我花了一些时间试图为此研究一个明确的答案,但找不到可靠的来源。

我的场景相当简单。我有一个带有消息泵设置的线程,它正在处理来自计时器的重复事件。这里是消息泵源:

// create timer that goes off every 500 ms
UINT_PTR myTimerID = SetTimer(NULL, 0, 500, TimerCallback);

// message structure
MSG msg;

// process and handle messages for this thread
BOOL getMessageStatus;
while((getMessageStatus = GetMessage(&msg, NULL, 0, 0)) != 0)
{
    // failed get message
    if(getMessageStatus == -1)
    {
        printf("GetMessage FAILED!\n");
    }
    // process timer message
    else if(msg.message == WM_TIMER)
    {
        // invoke callback
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

如果 TimerCallback 花费的时间超过 500 毫秒,则计时器将再次触发其事件。由于回调与消息泵在同一线程上执行,因此我假设回调必须在消息泵处理下一条计时器消息之前完成。

对吗?

【问题讨论】:

    标签: winapi win32gui


    【解决方案1】:

    SetTimer() 是一个基于消息的计时器。当计时器结束时,它会在消息队列中设置一个特殊标志。当您在队列中抽取新消息时,如果已设置该标志并且其他更高优先级的消息不在队列中等待,则将创建 WM_TIMER 消息。当您的代码忙于调度生成的WM_TIMER 消息时,计时器可以在后台运行并再次设置标志,从而在您下次抽出消息队列时生成新的WM_TIMER 消息。因此,在回调中直接或通过模式对话框发送消息时要小心,因为这可能会导致定时器回调的递归调用,从而可能导致堆栈溢出。但是,如果您的消息泵送仅在您的主线程循环中,那么您会没事的。

    【讨论】:

      【解决方案2】:

      只要处理消息只有一个入口点,一次只能处理一条消息。您可以通过在已经运行的事件处理程序中处理更多消息来搞砸事情,但不要这样做,您应该没问题。

      【讨论】:

        猜你喜欢
        • 2015-12-23
        • 2019-10-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-20
        • 2016-09-28
        • 1970-01-01
        • 2017-02-23
        相关资源
        最近更新 更多