【问题标题】:C++ How can i trigger that a PostMessage was proceed in another threadC++ 如何触发 PostMessage 在另一个线程中进行
【发布时间】:2016-07-29 15:19:55
【问题描述】:

我有一个 MFC-C++ 应用程序,其中至少有两个线程在运行“MainFrame”(=GUI 线程)和一个“Solver”线程。

在某一时刻,第二个线程(Solver)启动了模型中的更改,GUI 线程应由PostMessage(...) 执行该更改。为了安全起见,我想等待该消息在第二个线程中继续进行。

通过使用SendMessage(...),Solver 线程等待消息被执行,但这样我们绕过了不应该成为目标的消息队列。

我的问题:在我继续之前,我怎样才能正确地检查/触发我的消息是否继续?

  1. 我们是否需要通过GetQueueStatus(...) 每 'x' 秒检查一次主线程消息队列的状态?
  2. 有没有办法让主线程向另一个线程发回“成功事件”?第二个等待事件返回?
  3. Boost 是否为此类问题提供了简单的解决方案?
  4. 是否已经有一个我没有找到的类似问题? (对不起)

我的功能:

void PostSequencerMessageToGUI(ESequencerSignal signal, CSchedulerStep * step)
{
    CMainFrame *mainFrame = theApp.GetMainFrame();
    assert(mainFrame);
    if (!mainFrame)
        return;
    mainFrame->PostMessage(WM_SEQUENCER_SIGNAL, signal, reinterpret_cast<LPARAM>(step));
    // mainFrame->SendMessage(WM_SEQUENCER_SIGNAL, signal, reinterpret_cast<LPARAM>(step));

    // Message was posted, now wait for event back to continue procedure
    // ... but how? ...and when to cancel ? ...
    return; 
}

【问题讨论】:

  • 错误在您的代码中。如果重要的话,无论是将消息发布到消息队列,还是直接传递到窗口过程,您都会遇到比这个更严重的问题。无论如何,如果您想要PostMessage 之类的回复,请使用SendMessageCallback
  • 只需使用线程同步对象,如自动重置事件,您使用 CreateEvent 创建的那种。处理完消息后,在 UI 线程中调用 SetEvent()。并在您的工作线程中使用 WaitForSingleObject()。如果您还需要传回“成功”,则将 bool 或 int 成员添加到 CSchedulerStep。
  • 使用 CreatEvent 和 SetEvent 可能也可以。

标签: c++ multithreading visual-c++ mfc message-queue


【解决方案1】:

由于 SendMessage 忽略当前消息队列(它通过队列),我无法使用这种方法。

我在另一个问题中找到了我的解决方案,该问题使用 Condition variablesMutex 解决。 https://stackoverflow.com/a/16909012/5036139

我的解决方案:

#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
boost::condition_variable g_sequencerJobCondition;
boost::mutex g_guiMutex;

void PostSequencerMessageToGUI(ESequencerSignal signal, CSchedulerStep * step)
{
    CMainFrame *mainFrame = theApp.GetMainFrame();
    assert(mainFrame);
    if (!mainFrame)
        return;

    bool work_is_done = false;

    try {
        boost::mutex::scoped_lock lock(g_guiMutex);
        mainFrame->PostMessage(WM_SEQUENCER_SIGNAL, reinterpret_cast<WPARAM>(&work_is_done), reinterpret_cast<LPARAM>(step));

        // Message was posted, now wait for event back to continue procedure
        while (!work_is_done){
            g_sequencerJobCondition.wait(lock);
        }
    } 
    catch (... /*e*/){
        // Handle all kind of exception like boost::thread_resource_error, boost::thread_interrupted, boost::exception, std::exception
        // ...
    }
    // ...
    return;
}

LRESULT CMainFrame::OnSequencerPostMessage( WPARAM wParam, LPARAM lParam )
{
    // ...
    bool *work_is_done = reinterpret_cast<bool*>(wParam);
    CSchedulerStep* step = reinterpret_cast<CSchedulerStep*>(lParam);

    // Handle business case ...
    // ...

    // Finally notify sequencer thread that the work is done
    work_is_done = true;
    g_sequencerJobCondition.notify_one();

    return true;
}

【讨论】:

  • 请将您找到的解决方案添加到您的答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多