Qt/C++ 如何在发出信号时等待一个插槽

Seb*_*Seb 1 c++ multithreading signals-slots qt5

我用 Qt/C++ 开发了一个应用程序,我使用信号/插槽机制在 2 个线程之间进行交互。第一个线程运行 UI/TreeWidget,第二个线程运行框架

我在一个操作上遇到了问题。

在 UI 方面,在开始我的操作之前,我在 UI 和框架之间连接信号/插槽,如下面的 treewidget.cpp

connect(&m_Framework, &Framework::RequestIfNameExist, this, &TreeWidget::RequestIfNameExist);
connect(this, &TreeWidget::SendAnswerIfNameExist, &m_Framework, &Framework::NotifIfNameExist);
Run Code Online (Sandbox Code Playgroud)

框架,启动并发送 RequestIfNameExist:

emit RequestIfNameExist(tmpname, item, fileInfo.isDir());

while(WaitingResponse == false){
    usleep(200);
}
Run Code Online (Sandbox Code Playgroud)

我添加了一个循环,因为我需要等待反馈。奇怪的是,在treewidget.cpp中,我从来没有进入

void TreeWidget::RequestIfNameExist(QString name, TreeWidgetItem *parent, bool isFolder) {
#ifdef PULS_LOG
    QLOG_INFO() << "[TreeWidget] [RequestIfNameExist] ";
#endif
    emit SendAnswerIfNameExist(isNameExist(name, parent), isFolder);
}
Run Code Online (Sandbox Code Playgroud)

我从不访问 TreeWidget 中的 RequestIfNameExist 但发出了信号。

我还在框架中放置了一个 while 循环以等待来自 TreeWidget 的反馈

void Framework::NotifIfNameExist(QTreeWidgetItem *item, bool isFolder){

    if(item != NULL)
        item->isFolder = isFolder;

    WaitingResponse = true;

}
Run Code Online (Sandbox Code Playgroud)

知道为什么框架发出的信号从未到达 treewidget 吗?是从那个时候来的吗??

有没有办法不使用while,例如“等待事件”+超时

谢谢

Jer*_*ner 5

我的第一个想法是,在另一个线程中的操作完成之前让任一线程阻塞是一种糟糕的设计——它在一定程度上违背了拥有多个线程的目的,即允许多个操作并行运行。如果您不小心,它也可能导致死锁(例如,如果两个线程决定几乎同时发出并等待!)

更好的设计是让启动方法执行emit RequestIfNameExit然后立即返回,以便启动线程的事件循环可以在操作期间照常继续运行。然后,当另一个线程完成它的工作时,它通过发出自己的响应信号来响应,导致第一个线程中的适当/连接的槽方法被调用,此时结果在第一个线程中被处理回。

也就是说,如果您坚持要阻止方法内的信号发射线程的执行,直到另一个线程完成执行关联的槽方法,您可以通过将信号/槽连接的类型设置为Qt::BlockingQueuedConnection(连接类型可以通过connect()的可选额外参数指定)。如果你这样做,那么你发出调用将不会返回,直到插槽方法(在另一个线程中)完成执行。鉴于此,您可以通过将指向数据对象的指针作为信号/槽方法签名中的参数之一传递给另一个线程,并让另一个线程根据需要填充该数据对象,从而从另一个线程获取结果。当发出返回时,您只需检查该数据对象的内容即可查看结果。