如何使用Qt-Dbus绑定而不阻塞主线程 [英] How to use Qt-Dbus bindings without blocking the main thread

查看:1609
本文介绍了如何使用Qt-Dbus绑定而不阻塞主线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是使用 Qt的DBus绑定创建库。



我试图创建一个Qt应用程序而不启动 QEventLoop (由



这里是一个简单的应用程序示例,使用QT-4.6.2版本工作正常,但内省时阻塞使用QT-4.8或更高版本。



DBusHandler.hpp

  #pragma once 
#include< iostream>
#include #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()<< std :: endl;
}
};

main.cpp

  #includeDBusHandler.hpp

int main(int ac,char ** av)
{
QCoreApplication (ac,av);
DBusHandler handler;

handler.moveToThread(& handler);

handler.start();
while(not handler.isRunning());

// app.exec();
sleep(10); //给出时间调用使用命令行:qdbus my.qdbus.example / local.DBusHandler.remoteCall a_message

handler.stop();
while(handler.isRunning());
}

正如你可以在 main.cpp 文件, app.exec()注释掉,但使应用程序在QT-4.8或更高版本(5.3.0)上正常工作。 / p>

我的问题是:可以使用Qt的DBus绑定调用 app.exec()

解决方案

其他线程 :有一个私人类名为 QDBusConnectionPrivate ,它继承自QObject并处理所有网络。很遗憾,如果您查看 qdbusconnection.cpp:1116 你会看到Qt硬编码 moveToThread code> QCoreApplication :: instance()



您应该提交一个增强请求以允许用户创建一个QDBusConnection使用用户指定的线程或事件循环。



在此期间,如果你愿意做一些危险的事情,你可以黑客自己通过创建你自己的 QDbusConnection 子类(我调用我的 SpecializedDBusConnection code>作为您想要将 QDbusConnectionPrivate 实例移动到的第三个参数。然后使用该类创建连接,而不是默认的 QDbusConnection :: sessionBus()



使用一些私有类,它需要包含一些私有头文件(在下面的代码中指出),而这又将尝试包括各种dbus库头,这将需要修改项目的 INCLUDEPATH 包括dbus库包含路径。



我已经验证这项工作在Qt 5.3.0和Qt 4.8.6。



DBusHandler.hpp

  #pragma once 
#include< iostream> ;
#include #include< QtCore / QtCore>
#include< QtDBus / QDBusInterface>
#include< QtDBus / QDBusConnectionInterface>

#include/path/to/Qt5.3.0/5.3/Src/qtbase/src/dbus/qdbusconnection_p.h

类SpecializedDBusConnection:public QDBusConnection {
const char * ownName;
public:
inline SpecializedDBusConnection(BusType类型,const char *名称,QThread *线程)
:QDBusConnection(connectToBus(type,QString :: fromLatin1(name))),ownName
{
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]


My goal is to create a library using the Qt's DBus bindings.

I tried to create a Qt application without launching the QEventLoop (provided by the QCoreApplication class) in the main thread.

Here is a minimalistic application sample, working fine using QT-4.6.2 version but blocking on introspection using QT-4.8 or higher.

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;
    }
};

main.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());
}

As you can see in the main.cpp file, app.exec() is commented out, but makes the application working fine on QT-4.8 or higher versions (5.3.0).

My question is the following: Is it possible to use the Qt's DBus bindings calling app.exec() in an other thread than the main one, on Qt-4.8 or 5.3 ?

解决方案

Background: There is a private class called QDBusConnectionPrivate which inherits from QObject and handles all networking. Unfortunately, if you look at qdbusconnection.cpp:1116 you'll see that Qt hard codes the moveToThread to QCoreApplication::instance().

You should probably submit an enhancement request to allow the user to create a QDBusConnection that uses a user specified thread or event loop.

In the meantime, if you're comfortable doing some dangerous things, you can hack it in yourself by creating your own QDbusConnection subclass (I called mine SpecializedDBusConnection) that takes QThread as a third argument of where you want the QDbusConnectionPrivate instance to be moved to. Then use that class to create the connection instead of the default QDbusConnection::sessionBus().

As this is using some private classes, it requires the inclusion of some private header files (noted in the code below) which in turn will attempt to include various dbus library headers which will necessitate the modifying of INCLUDEPATH of the project to include the dbus library include path.

I've verified this works on Qt 5.3.0 and Qt 4.8.6.

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]

这篇关于如何使用Qt-Dbus绑定而不阻塞主线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆