与不是主线程的GUI线程进行通信

时间:2019-09-22 13:17:15

标签: c++ multithreading qt c++11 qt5

我设法在工作器C ++ std::thread中实现了基于GUI Qt的应用程序,如here所述。现在,我需要主线程和辅助线程进行通信。

我的问题是:如何从主线程向工作线程传递消息(浮点数数组),以便更新GUI?

我有一个执行实时信号处理的应用程序。我的目标是创建一个Qt GUI,可以将其插入到我的应用程序中,以可视化各种信号,而不会影响实时性。我研究了如何完成此操作的不同方法,并得出结论,此post非常详细地描述了我需要的内容并提供了解决方案。但是,没有有关主线程和工作线程如何相互通信的信息。

我尝试使用here中描述的Futures / Promises方法来完成线程间通信。尽管我可以使该示例运行,但无法将其集成到我的项目中。原因是这种方法依赖于工作线程内部有一个繁忙的循环,该循环不断检查主线程是否已发送新消息。但是,在Qt应用程序中,程序一旦进入a.exec()中的主事件循环,便会阻塞。这样可以防止繁忙的循环检查,从而导致程序死锁。

这就是我生成GUI工作线程的方式(基于this发布)。

#include <thread>

// Start the Qt realtime plot demo in a worker thread
int argc = 0;
char **argv = NULL;
std::thread t1
        (
                [&] {
                    QApplication application(argc, argv);
                    MainWindow mainWindow;
                    mainWindow.show();
                    return application.exec();
                }
        );

2 个答案:

答案 0 :(得分:1)

您可以使用Qt自己的方法在线程之间进行通信。每个Qt对象都有一个线程亲和力。如果在单独的GUI线程中创建MainWindow对象,则该对象将附加到该线程。如果您使用Qt信号和插槽并将其与Qt::QueuedConnection连接,则无论该信号来自何处,都会通过该线程的主循环在对象的线程中调用该插槽。

请注意,您可以在MainWindow类中定义信号,但是由于它们是公共的,因此可以从外部调用它们。这意味着您不需要单独的发送对象。例如,在MainWindow构造函数中,您可以将其自身的信号连接到slot或lambda方法。

要发出MainWindow信号,可以在GUI线程外将MainWindow指针设置为nullptr,然后将该指针(通过lambda捕获)设置为在内部创建的新对象GUI线程。在线程外,只要您想发出信号,就可以做某事。像if (mainWindow) mainWindow->signal(…)。我认为您仍然需要检查,因为您的GUI是可选的。

两个注意事项:

  1. 您也可以使用QMetaObject::invokeMethod放弃信号,它删除了样板,但是可以通过引用在编译时检查的class方法来连接信号; QMetaObject方法在运行时使用字符串匹配。同样,在公共信号但插槽受保护的情况下,您可以确保外部代码不会意外地直接调用方法。
  2. 将信号连接到lambda时,请确保指定接收对象。 connect(this, &MainWindow::signal, this, [this] {…});将在接收线程中执行lambda,而connect(this, &MainWindow::signal, [this] {…});

答案 1 :(得分:0)

对于信号处理,您通常不需要qts虚拟调用的开销。除此之外,

在git@github.com:midjji / convenient_multithreaded_qt_gui.git

中找到了用于gui通讯线程的好解决方案。

然后仅是

enter code here
run_in_gui_thread(new RunEventImpl([](){
        QMainWindow* window=new QMainWindow();
        window->show();
    }));

随时可以在任何线程中调用,同时还要在bg中为您进行设置。