代码之家  ›  专栏  ›  技术社区  ›  Coder

通过后消息将MFC数据转发到主线程

  •  5
  • Coder  · 技术社区  · 14 年前

    我有一个C++/MFC应用程序需要重构。这个应用程序用于处理主线程上的大部分数据,因此会阻塞输入,现在我想更改它,以便所有的GUI更新都是通过后消息完成的。

    不幸的是,我似乎找不到一个关于如何实现这个目标的好来源。

    现在,我正在考虑创建一个优先级队列,受关键部分保护,一个处理此队列的工作线程(while(true)),以及将指向数据的指针发送到主线程的后消息机制。

    这种方法让我感到害怕的是,邮件根本不能保证到达主线程,因此,如果我理解正确,就有可能发生内存泄漏。

    第二个问题是,另一个应用程序可以向我的应用程序发送自定义消息,而我的应用程序可能试图取消引用wparam或lparam作为指针,从而导致av。

    有人知道这些任务的最佳实践是什么吗?

    数据可以是Web控件的HTML内容,也可以是列表框、下拉列表等的其他内容。

    3 回复  |  直到 14 年前
        1
  •  11
  •   John Dibling    14 年前

    你的信息会到达那里。我不知道你为什么认为邮电不一定有效——确实如此。(编辑:假设postmessage()返回true!检查您的返回代码!)

    您希望避免使用队列在线程之间通信数据。任何由两个线程访问的队列都需要受到保护。在两侧添加硬锁将序列化您的应用程序。

    相反,在堆上使用 new 它包含您的数据,然后告诉另一个线程“我已经为您获得了数据,现在它就在这里。”接收线程随后拥有该数据指针的所有权,并负责 delete 就这样。这样做,没有硬锁。

    现在唯一的诀窍是找出“告诉另一条线”的部分,但这也很容易。

    如果要将数据从工作线程发送到主线程,只需使用 PostMessage() :

    worker_thread_proc()
    {
    // ..
    
      // Create the data object you're going to pass to the MT
      MyData* data = new MyData;
      data->some_value_ = "foo";
    
      // Pass it:
      PostMessage(main_wnd, WM_YOU_HAVE_DATA, reinterpret_cast<WPARAM>(data), 0);
    }
    

    …主线程处理此问题,然后删除数据:

    MainWnd::OnYouHaveData(WPARAM wp, LPARAM)
    {
      std::auto_ptr<MyData> data(reinterpret_cast<MyData*>(wp));
      my_widget->set_text(data->some_value_); // you get the idea
    }
    

    如果您担心外部应用程序的自定义消息会碰到您的应用程序,您可以让Windows使用 RegisterWindowsMessage() --你唯一的挑战是为你的信息选择正确的名字。

    如果您将数据从主线程发送到工作线程,则可以执行上述操作,除非使用 后消息() 要通过墙发送数据,可以使用 QueueUserAPC() (确保您的员工Thead处于可提醒的等待状态——阅读链接文档中的备注)或 PostThreadMessage() .

    编辑:

    根据您在OP中的评论,现在我理解了为什么您担心postmessage()不起作用。

    是的,Windows消息队列大小有一个硬限制。默认情况下,队列中只能有4000条消息。(注册表设置最多可将此值调整为10000)。

    如果队列已满,则调用 后消息() 将失败并显示错误代码。当您检查getLastError()(我不记得它现在返回的错误代码)时,很明显消息队列已满。

    听起来不像母鸡,但您确实需要检查API调用的返回值。但除此之外,如果您在消息队列上限中运行,那么我认为您的应用程序无论如何都会被破坏。当队列已满时,应用程序将无法呼吸。屏幕不会画画,你做的任何处理都会过时,所有的坏事都会发生。如果这就是你所处的情况,你可能需要看看原因。

        2
  •  2
  •   Mark Ransom    14 年前

    使用两个队列,一个用于发送到工作线程的工作请求,另一个用于返回主线程的结果。您可以使用postmessage唤醒主线程并告诉它检查队列,但消息中不需要任何参数。

        3
  •  1
  •   Alex Emelianov    14 年前

    我不久前解决了一个类似的问题。我创建了一个单例队列来保存需要从后台线程流到UI(主)线程的数据(或操作)。队列受关键部分保护。后台线程会将其数据放入队列并发布消息。消息不包含任何数据,它充当一个简单的唤醒调用,“嘿,主线程,看看队列,你有工作”。

    这样,您就不会冒泄漏任何内存或其他资源的风险;队列可以安全地用它包含的所有数据销毁。