Question

Mon objectif est de créer une bibliothèque en utilisant le Liaisons DBus de Qt.

J'ai essayé de créer une application Qt sans lancer le QEventLoop (fourni par le QCoreApplication classe) dans le fil principal.

Voici un exemple d'application minimaliste, fonctionnant correctement avec la version QT-4.6.2 mais bloquant l'introspection avec QT-4.8 ou une version ultérieure.

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

Comme vous pouvez le voir dans le main.cpp déposer, app.exec() est commenté, mais permet à l'application de fonctionner correctement sur QT-4.8 ou les versions supérieures (5.3.0).

Ma question est la suivante :Est-il possible d'utiliser les liaisons DBus de Qt en appelant app.exec() dans un autre fil que le principal, sur Qt-4.8 ou 5.3 ?

Était-ce utile?

La solution

Arrière-plan:Il existe un cours privé appelé QDBusConnectionPrivate qui hérite de QObject et gère tous les réseaux.Malheureusement, si vous regardez qdbusconnection.cpp:1116 vous verrez que Qt code en dur le moveToThread à QCoreApplication::instance().

Vous devriez probablement soumettre une demande d'amélioration pour permettre à l'utilisateur de créer un QDBusConnection qui utilise un thread ou une boucle d'événement spécifié par l'utilisateur. Voir mise à jour ci-dessous.

En attendant, si vous êtes à l'aise pour faire des choses dangereuses, vous pouvez le pirater vous-même en créant les vôtres QDbusConnection sous-classe (j'ai appelé la mienne SpecializedDBusConnection) qui prend QThread comme troisième argument pour savoir où vous voulez que QDbusConnectionPrivate instance vers laquelle déplacer.Utilisez ensuite cette classe pour créer la connexion au lieu de la valeur par défaut QDbusConnection::sessionBus().

Comme cela utilise certaines classes privées, cela nécessite l'inclusion de certains fichiers d'en-tête privés (indiqués dans le code ci-dessous) qui tenteront à leur tour d'inclure divers en-têtes de bibliothèque dbus, ce qui nécessitera la modification de INCLUREPATH du projet pour inclure le chemin d'inclusion de la bibliothèque dbus.

J'ai vérifié que cela fonctionne sur Qt 5.3.0 et Qt 4.8.6.

Mise à jour: Dans Qt 5.6, QtDBus a été refactorisé pour utiliser les threads pour le traitement des messages entrants/sortants ;plus de blocage du thread principal !

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]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top