如何在不阻塞主线程的情况下使用 Qt-Dbus 绑定
-
26-12-2019 - |
题
我的目标是使用创建一个库 Qt 的 DBus 绑定.
我尝试创建一个 Qt 应用程序而不启动 QEventLoop
(由提供 QCoreApplication
类)在主线程中。
这是一个简约的应用程序示例,使用 QT-4.6.2 版本工作正常,但使用 QT-4.8 或更高版本会阻止内省。
DBusHandler.hpp
#pragma once
#include <iostream>
#include <QtCore/QThread>
#include <QtCore/QtCore>
#include <QtDBus/QDBusInterface>
class DBusHandler : public QThread
{
Q_OBJECT;
private:
void run(void)
{
QDBusConnection connection = QDBusConnection::sessionBus();
connection.registerService("my.qdbus.example");
connection.registerObject("/", this, QDBusConnection::ExportAllSlots);
exec();
}
public:
DBusHandler(void) {}
virtual ~DBusHandler(void) {}
void stop(void)
{
QDBusConnection connection = QDBusConnection::sessionBus();
connection.unregisterObject("/");
connection.unregisterService("my.qdbus.example");
connection.disconnectFromBus(connection.name());
QThread::quit();
}
public slots:
void remoteCall(QByteArray message)
{
std::cout << "Message size: " << message.size() << std::endl;
}
};
主程序
#include "DBusHandler.hpp"
int main(int ac, char **av)
{
QCoreApplication app(ac, av);
DBusHandler handler;
handler.moveToThread(&handler);
handler.start();
while (not handler.isRunning());
// app.exec();
sleep(10); // Gives time to call using the command line: "qdbus my.qdbus.example / local.DBusHandler.remoteCall a_message"
handler.stop();
while (handler.isRunning());
}
正如你在 main.cpp
文件, app.exec()
被注释掉,但使应用程序在 QT-4.8 或更高版本(5.3.0)上正常工作。
我的问题如下:是否可以使用 Qt 的 DBus 绑定调用 app.exec()
在一个 其他线程 比主要的,在 Qt-4.8 或 5.3 上?
解决方案
背景: :有一个私人班级叫 QDBusConnectionPrivate
它继承自 QObject 并处理所有网络。不幸的是,如果你看 qdbusconnection.cpp:1116
你会看到 Qt 硬编码了 moveToThread
到 QCoreApplication::instance()
.
您可能应该提交一个增强请求,以允许用户创建使用用户指定的线程或事件循环的 QDBusConnection。 请参阅下面的更新。
同时, ,如果你愿意做一些危险的事情,你可以通过创建自己的东西来破解它 QDbusConnection
子类(我称之为我的 SpecializedDBusConnection
)这需要 QThread
作为你想要的第三个参数 QDbusConnectionPrivate
要移动到的实例。然后使用该类来创建连接而不是默认的连接 QDbusConnection::sessionBus()
.
由于这是使用一些私有类,因此需要包含一些私有头文件(在下面的代码中注明),这些文件反过来将尝试包含各种 dbus 库头文件,这将需要修改 包含路径 项目的包含 dbus 库的包含路径。
我已经验证这适用于 Qt 5.3.0 和 Qt 4.8.6。
更新: 在 Qt 5.6,QtDBus 被重构为使用线程 用于传入/传出消息处理;不再阻塞主线程!
DBusHandler.hpp
#pragma once
#include <iostream>
#include <QtCore/QThread>
#include <QtCore/QtCore>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnectionInterface>
#include "/path/to/Qt5.3.0/5.3/Src/qtbase/src/dbus/qdbusconnection_p.h"
class SpecializedDBusConnection : public QDBusConnection {
const char *ownName;
public:
inline SpecializedDBusConnection(BusType type, const char *name, QThread *thread)
: QDBusConnection(connectToBus(type, QString::fromLatin1(name))), ownName(name)
{
if (QDBusConnectionPrivate::d(*this)) {
QDBusConnectionPrivate::d(*this)->moveToThread(thread);
}
}
inline ~SpecializedDBusConnection()
{ disconnectFromBus(QString::fromLatin1(ownName)); }
};
class DBusHandler : public QThread
{
Q_OBJECT;
private:
void run(void)
{
QDBusConnection connection = SpecializedDBusConnection(QDBusConnection::SessionBus, "qt_default_session_bus", this);
connection.registerService("my.qdbus.example");
connection.registerObject("/", this, QDBusConnection::ExportAllSlots);
exec();
}
[snip]