メインスレッドをブロックせずに Qt-Dbus バインディングを使用する方法

StackOverflow https://stackoverflow.com//questions/24058519

質問

私の目標は、 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;
    }
};

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

ご覧のとおり、 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 がハードコードしていることがわかります。 moveToThreadQCoreApplication::instance().

おそらく、ユーザーが指定したスレッドまたはイベント ループを使用する QDBusConnection を作成できるようにする機能拡張リクエストを送信する必要があります。 以下のアップデートを参照してください。

その間に, 、危険なことをすることに抵抗がない場合は、独自のを作成して自分自身をハッキングできます。 QDbusConnection サブクラス (私は自分のものと呼びました) SpecializedDBusConnection) かかります QThread 必要な場所の 3 番目の引数として、 QDbusConnectionPrivate 移動先のインスタンス。次に、デフォルトの代わりにそのクラスを使用して接続を作成します。 QDbusConnection::sessionBus().

これはいくつかのプライベート クラスを使用しているため、いくつかのプライベート ヘッダー ファイル (以下のコードに記載) をインクルードする必要があり、その結果、さまざまな dbus ライブラリ ヘッダーをインクルードしようとするため、次の変更が必要になります。 IncludePATH 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]
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top