Pregunta

Mi objetivo es crear una biblioteca usando el Enlaces DBus de Qt.

Intenté crear una aplicación Qt sin iniciar el QEventLoop (proporcionado por el QCoreApplication clase) en el hilo principal.

Aquí hay un ejemplo de aplicación minimalista, que funciona bien con la versión QT-4.6.2 pero bloquea la introspección con QT-4.8 o superior.

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

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

Como puedes ver en el main.cpp archivo, app.exec() está comentado, pero hace que la aplicación funcione bien en QT-4.8 o versiones superiores (5.3.0).

Mi pregunta es la siguiente:¿Es posible utilizar las llamadas de enlaces DBus de Qt? app.exec() en un otro hilo que el principal, en Qt-4.8 o 5.3?

¿Fue útil?

Solución

Fondo:Hay una clase privada llamada QDBusConnectionPrivate que hereda de QObject y maneja todas las redes.Desafortunadamente, si miras qdbusconnection.cpp:1116 Verás que Qt codifica el moveToThread a QCoreApplication::instance().

Probablemente debería enviar una solicitud de mejora para permitir al usuario crear una QDBusConnection que utilice un hilo o bucle de eventos especificado por el usuario. Vea la actualización a continuación.

Mientras tanto, si te sientes cómodo haciendo algunas cosas peligrosas, puedes hackearlas tú mismo creando las tuyas propias QDbusConnection subclase (yo llamé a la mía SpecializedDBusConnection) eso toma QThread como tercer argumento de donde quieres el QDbusConnectionPrivate instancia a la que se trasladará.Luego use esa clase para crear la conexión en lugar de la predeterminada QDbusConnection::sessionBus().

Como se utilizan algunas clases privadas, se requiere la inclusión de algunos archivos de encabezado privados (anotados en el código siguiente) que a su vez intentarán incluir varios encabezados de biblioteca dbus que requerirán la modificación de INCLUYERUTA del proyecto para incluir la ruta de inclusión de la biblioteca dbus.

Verifiqué que esto funciona en Qt 5.3.0 y Qt 4.8.6.

Actualizar: En Qt 5.6, QtDBus fue refactorizado para usar subprocesos para procesamiento de mensajes entrantes/salientes;¡No más bloqueos del hilo 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]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top