Domanda

Il mio obiettivo è quello di creare una libreria di utilizzo Qt DBus associazioni.

Ho provato a creare un'applicazione Qt senza lanciare il QEventLoop (fornito dal QCoreApplication classe) nel thread principale.

Qui è un minimalista applicazione di esempio, lavorando bene con le QT 4.6.2 versione, ma il blocco sull'introspezione utilizzando QT 4.8 o superiore.

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

Come si può vedere nel main.cpp file, app.exec() non è commentata, ma rende l'applicazione funziona bene su QT 4.8 o versioni superiori (5.3.0).

La mia domanda è la seguente:È possibile utilizzare Qt DBus associazioni di chiamata app.exec() in un altro thread da quello principale, su Qt 4.8 5.3 ?

È stato utile?

Soluzione

Sfondo:C'è una classe privata denominato QDBusConnectionPrivate che eredita da QObject, e gestisce tutta la rete.Purtroppo, se si guarda qdbusconnection.cpp:1116 vedrai che Qt hard codici moveToThread per QCoreApplication::instance().

Probabilmente si dovrebbe presentare una richiesta di miglioramento per consentire all'utente di creare un QDBusConnection che utilizza un utente specificato il filetto o il ciclo di eventi. Vedere aggiornamento di seguito.

Nel frattempo, se sei comodo fare certe cose pericolose, è possibile hack è in te creando il proprio QDbusConnection sottoclasse (io la mia chiamata SpecializedDBusConnection) che si QThread come terzo argomento di cui si desidera che il QDbusConnectionPrivate istanza per essere spostato.Quindi utilizzare la classe per creare la connessione, invece di quella di default QDbusConnection::sessionBus().

Questo è l'utilizzo di alcune lezioni private, richiede l'inserimento di alcuni file di intestazione private (indicato nel codice riportato di seguito) che a sua volta cercherà di includere vari dbus header di libreria, che richiederà la modifica della INCLUDEPATH il progetto dbus libreria percorso di inclusione.

Ho verificato questo funziona su Qt 5.3.0 e Qt 4.8.6.

Aggiornamento: In Qt 5.6, QtDBus è stato riscritto per utilizzare i thread in arrivo/in uscita di elaborazione del messaggio;non più il blocco del thread principale!

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]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top