Frage

Mein Ziel ist es, eine Bibliothek mit dem zu erstellen Qts DBus-Bindungen.

Ich habe versucht, eine Qt-Anwendung zu erstellen, ohne sie zu starten QEventLoop (bereitgestellt von der QCoreApplication Klasse) im Hauptthread.

Hier ist ein minimalistisches Anwendungsbeispiel, das mit der Version QT-4.6.2 einwandfrei funktioniert, aber mit QT-4.8 oder höher die Introspektion blockiert.

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

Wie Sie in der sehen können main.cpp Datei, app.exec() ist auskommentiert, sorgt aber dafür, dass die Anwendung unter QT-4.8 oder höheren Versionen (5.3.0) einwandfrei funktioniert.

Meine Frage ist folgende:Ist es möglich, die DBus-Bindungsaufrufe von Qt zu verwenden? app.exec() in einem (n anderer Thread als die Hauptversion, auf Qt-4.8 oder 5.3?

War es hilfreich?

Lösung

Hintergrund:Es gibt eine private Klasse namens QDBusConnectionPrivate das von QObject erbt und alle Netzwerkfunktionen übernimmt.Leider, wenn man hinschaut qdbusconnection.cpp:1116 Sie werden sehen, dass Qt das fest codiert moveToThread Zu QCoreApplication::instance().

Sie sollten wahrscheinlich eine Erweiterungsanforderung einreichen, um dem Benutzer die Erstellung einer QDBusConnection zu ermöglichen, die einen vom Benutzer angegebenen Thread oder eine Ereignisschleife verwendet. Siehe Update unten.

In der Zwischenzeit, Wenn Sie gerne gefährliche Dinge tun, können Sie sie selbst hacken, indem Sie Ihre eigenen erstellen QDbusConnection Unterklasse (ich habe meine aufgerufen SpecializedDBusConnection) das macht QThread als drittes Argument dafür, wo Sie das wollen QDbusConnectionPrivate Instanz, in die verschoben werden soll.Verwenden Sie dann diese Klasse, um die Verbindung anstelle der Standardverbindung zu erstellen QDbusConnection::sessionBus().

Da hierbei einige private Klassen verwendet werden, ist die Einbindung einiger privater Header-Dateien erforderlich (siehe Code unten), die wiederum versuchen, verschiedene Header der Dbus-Bibliothek einzubinden, was eine Änderung von erfordert INCLUDEPATH des Projekts, um den Include-Pfad der dbus-Bibliothek einzuschließen.

Ich habe überprüft, dass dies auf Qt 5.3.0 und Qt 4.8.6 funktioniert.

Aktualisieren: In Qt 5.6, QtDBus wurde umgestaltet, um Threads zu verwenden für die Verarbeitung eingehender/ausgehender Nachrichten;Kein Blockieren des Hauptthreads mehr!

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]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top