pthread 2 信号和插槽包装器 mit QEventLoop



problem

我目前正在将 FUSE 与 qt5 放在一起。 Qt 和 FUSE 之间还没有桥梁,FUSE 主线程(它正在生成其他工作 FUSE 线程)和 QCoreApplication 只是并排运行。

但我希望能够使用 Qt 的信号和插槽在基于 QObject 的对象和 [0] 中所示的 pthread's Read(..) 函数之间发送和接收数据。

问题

现在我想将 Read(..) 函数从 [0] 更改为使用 Qt 的信号和插槽从基于 QObject 的类中检索数据。 从 pthread 发送信号是有效的,但没有明确的 QEventLoop,我无法收到回复。 因此,我正在查看 [1] 中的代码,它在设计上非常出色,但我还没有让它工作。

伪代码(取自 [1]):

QNetworkAccessManager qnam;
QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(...)));
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
/* reply has finished, use it */

看起来很有趣,我所需要的只是一个类似于QNetworkRep的QObject派生类来处理请求。

当我玩那个代码时,我遇到了一个问题,我的QNetworkReprat实现不会等待loop.exec()运行,然后loop不会接收finish()信号。

但是,难道没有比生成QEventLoop更容易的事情吗?

注意:[1] 示例中的 QNetworkReply 和 QNetworkAccessManager 是在 pthread 中生成的,但是,我需要能够使用 SIGNALS 和 SLOTS 与 QCoreApplication 的偶数队列进行通信,因为包含数据的对象来自不同的 QThread(在此中是 QCoreApplication 或特殊的 QThread)。

使用 Qt::QueuedConnection

我还找到了 [2],也许:

connect(src, SIGNAL(signal-signature), dest, SLOT(slot-signature), Qt::QueuedConnection);

是我想要的一切,但我对此表示怀疑。

链接

  • [0] https://github.com/qknight/qt-fuse-example/blob/4d92a74fad22fd559588e58be67f766174c7efb8/qt-fuse/examplefs.cc#L74
  • [1] http://qt-project.org/wiki/ThreadsEventsQObjects#7494f2b4836907fc1c09311e3a0305e6
  • [2] 从非 Qt 线程或 Qt 主事件循环发出 Qt 信号,频率为 4.5
您可能

面临的是QNetworkAccessManager内部使用线程来处理http请求。这就是为什么它"不等"你。需要相当简单的修改来修复它:

QNetworkAccessManager qnam;
QEventLoop loop;
QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(...)));
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
if (!reply->isFinished()) loop.exec();

在多线程中使用 QObjects 时需要注意的事项

当作为信号源的对象位于(实例化)与具有插槽的对象的线程不同的线程中时,连接将自动为QueuedConnection类型。

真正的问题是:每个QObject都有一个线程亲和力。默认相关性是实例化对象的线程。您不应该直接从其他线程使用此类对象。

您可能要做的是在同一线程中实例化发送方和接收方对象,然后从另一个线程发出信号。这是潜在错误错误的根源,如果此类对象的用户强制非自动直接连接,则会导致未定义的行为。

无论何时执行emit object->signal(...),以下不变性应成立:

Q_ASSERT(QThread::currentThread() == object->thread());

随意在显式执行的每个emit()前面添加这些固定检查。

如果断言失败,则需要使用 QObject::moveToThread 将对象移动到要触发其信号的线程。可以通过从pthread中运行的代码调用QThread::currentThread()来获取给定pthreadQThread。将自动为您创建QThread实例:)

是的,你想要Qt::QueuedConnection方法。但也要确保您使用的是多线程Qt库。IIRC 这是一个构建时选项。

另请参阅:Qt文档

最新更新