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()
来获取给定pthread
的QThread
。将自动为您创建QThread
实例:)
是的,你想要Qt::QueuedConnection方法。但也要确保您使用的是多线程Qt库。IIRC 这是一个构建时选项。
另请参阅:Qt文档