Как использовать привязки Qt-Dbus, не блокируя основной поток

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

Вопрос

Моя цель состоит в том, чтобы создать библиотеку, используя Привязки DBus Qt к DBus.

Я попытался создать Qt-приложение без запуска QEventLoop (предоставлено QCoreApplication класс) в основном потоке.

Вот минималистичный пример приложения, отлично работающего с использованием версии QT-4.6.2, но блокирующего самоанализ с использованием QT-4.8 или выше.

DBusHandler.гэс

#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).

Мой вопрос заключается в следующем:Можно ли использовать привязки DBus Qt, вызывающие app.exec() в другой поток чем основной, на Qt-4.8 или 5.3 ?

Это было полезно?

Решение

Предыстория:Существует частный класс под названием QDBusConnectionPrivate который наследуется от QObject и обрабатывает все сетевые подключения.К сожалению, если вы посмотрите на qdbusconnection.cpp:1116 вы увидите, что Qt жестко кодирует moveToThread Для QCoreApplication::instance().

Вероятно, вам следует отправить запрос на улучшение, чтобы разрешить пользователю создавать QDBusConnection, который использует указанный пользователем поток или цикл событий. Смотрите обновление ниже.

В то же время, если вам комфортно заниматься какими-то опасными вещами, вы можете взломать это в себе, создав свой собственный QDbusConnection подкласс (я назвал свой SpecializedDBusConnection) это требует QThread в качестве третьего аргумента того, где вы хотите QDbusConnectionPrivate экземпляр, в который нужно переместить.Затем используйте этот класс для создания соединения вместо используемого по умолчанию QDbusConnection::sessionBus().

Поскольку при этом используются некоторые частные классы, это требует включения некоторых файлов частных заголовков (указанных в приведенном ниже коде), которые, в свою очередь, будут пытаться включить различные заголовки библиотеки dbus, что потребует изменения INCLUDEPATH ВКЛЮЧИТЬ ПУТЬ проекта для включения библиотеки dbus включает путь.

Я убедился, что это работает на Qt 5.3.0 и Qt 4.8.6.

Обновить: В Qt 5.6, QtDBus был реорганизован для использования потоков для обработки входящих /исходящих сообщений;больше никакой блокировки основного потока!

DBusHandler.гэс

#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