【问题标题】:How to use Qt-Dbus bindings without blocking the main thread如何在不阻塞主线程的情况下使用 Qt-Dbus 绑定
【发布时间】:2014-07-26 08:20:55
【问题描述】:

我的目标是使用Qt's DBus bindings 创建一个库。

我试图创建一个 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;
    }
};

ma​​in.cpp

#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-4.8 或 5.3 上的其他线程中使用调用 app.exec() 的 Qt 的 DBus 绑定?

【问题讨论】:

  • @naab 我很困惑。 OP 询问“是否可以在 Qt-4.8 或 5.3 的主线程中使用 Qt 的 DBus 绑定没有 app.exec() 调用?”。不应该是with吗,按照他的表现?
  • @Tay2510 演示表明,在主线程中不执行app.exec(),代码在Qt 4.6.2下工作。预期的解决方案是在不阻塞主线程的情况下使用 Qt EventLoops 的某种方式。是否可以从 4.8.4 版本开始使用 Qt 作为库而不阻塞主线程并使用 QEventLoops(使信号/插槽工作)?
  • @naab 所以你问了一个与 OP 不同的问题,还是我应该说 OP 提出了一个错误的问题?因为您说“不是有可能......不阻塞主线程”,而 OP 询问“是否有可能......没有app.exec() 调用主线”。对不起,我不是故意玩文字的,我只是想确定问题出在哪里。因为没有app.exec() 的情况已经在 4.8 上进行了演示和工作,为什么我们还要再次要求 without
  • @naab 没关系,Jules Baratoux 刚刚编辑了这篇文章。看来原来的问题有点误导。

标签: c++ qt introspection dbus qeventloop


【解决方案1】:

背景:有一个名为QDBusConnectionPrivate 的私有类继承自QObject 并处理所有网络。不幸的是,如果您查看qdbusconnection.cpp:1116,您会发现Qt 将moveToThread 硬编码为QCoreApplication::instance()

您可能应该提交增强请求以允许用户创建使用用户指定线程或事件循环的 QDBusConnection。 请参阅下面的更新。

与此同时,如果您愿意做一些危险的事情,您可以通过创建自己的 QDbusConnection 子类(我叫我的 SpecializedDBusConnection)来破解它,该子类采用 @987654330 @ 作为您希望将 QDbusConnectionPrivate 实例移动到的位置的第三个参数。然后使用该类而不是默认的QDbusConnection::sessionBus() 创建连接。

由于这使用了一些私有类,它需要包含一些私有头文件(在下面的代码中注明),这反过来会尝试包含各种 dbus 库头,这将需要修改 INCLUDEPATH 项目的包含 dbus 库的包含路径。

我已在 Qt 5.3.0 和 Qt 4.8.6 上验证了此功能。

更新:Qt 5.6, QtDBus was refactored to use threads 中用于传入/传出消息处理;不再阻塞主线程!

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]

【讨论】:

  • 非常感谢您花时间研究它。还没有测试它,但我想这是要走的路。仍在徘徊为什么他们删除了这个 moveToThread 调用。 if you're comfortable doing some dangerous things => 恕我直言,您的解决方案远非肮脏/危险的方式:)。无论如何都很好,完全值得赏金!
  • @Linville 非常感谢您的回复!我会测试你的解决方案
猜你喜欢
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-24
  • 1970-01-01
相关资源
最近更新 更多