AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / user-8719823

bbdd's questions

Martin Hope
bbdd
Asked: 2025-04-05 22:13:04 +0800 CST

Como otimizar um Gerenciador de Eventos em uma arquitetura de plugin modular Qt/C++ para melhorar o desempenho?

  • 7

No momento, minha tarefa é desenvolver um aplicativo para desenho. Para resolver esse problema, foi decidido usar QT/C++ . Como esta é a primeira vez na minha carreira que estou desenvolvendo um aplicativo GUI que consiste em um grande número de módulos, plug-ins e lógica, foi decidido usar um EventManager para comunicar todos os módulos entre si.

Quase todos os módulos (plugins) não sabem sobre a existência de outros módulos e se comunicam com o aplicativo principal usando o mesmo gerenciador de eventos enviando eventos para ele ou esperando por eventos. Mas há plugins que enviam eventos com muita frequência, o que afeta o desempenho. Como otimizar o gerenciador de eventos para melhor desempenho. Como exemplo, apresento abaixo um instantâneo de como os módulos existem isolados uns dos outros e se comunicam com a "Página de desenho" apenas enviando mensagens.

Arquitetura abstrata de comunicação entre módulos e a janela principal

O Gerenciador de Eventos em si é uma classe estática simples que recebe uma string como o tipo de evento e QVariant como o parâmetro deste evento!


// event-manager.h

#include <QObject>
#include <functional>
        
class EventManager final :
    public QObject
{
    Q_OBJECT

public:

    using EventCallback = std::function<void(const QString&, const QVariant&)>;

    void triggerEvent(const QString &eventName, const QVariant& value) noexcept;
    void registerEvent(const QString &eventName, QObject *receiver, EventCallback) noexcept;
    void unregisterEvent(const QString &eventName, QObject *receiver) noexcept;

    static EventManager& instance() noexcept;

signals:

    void eventTriggered(const QString &eventName, const QVariant& value);

private:

    explicit EventManager(QObject *parent = nullptr);
    virtual ~EventManager() override;

private:

    struct Private;
    Private *d_ptr;

};

// event-manager.cpp

#include "event-manager.cpp"

#include <QHash>
#include <QMap>
#include <QMutex>
#include <QMutexLocker>
#include <QPointer>
#include <QVariant>

struct EventManager::Private {

    struct EventSlot {
        QPointer<QObject> receiver;
        EventCallback     callback;
    };

    QMutex                          mutex;
    QMap<QString, QList<EventSlot>> events;
};

EventManager::EventManager(QObject *aParent) :
    QObject(aParent),
    d_ptr(new EventManager::Private)
{}

EventManager::~EventManager()
{
    delete d_ptr; 
}

void EventManager::triggerEvent(const QString&  aEventName, const QVariant& aValue) noexcept
{
    if (!aEventName.isEmpty()) {
        QMutexLocker locker(&d_ptr->mutex);
        const bool found = d_ptr->events.contains(aEventName);
        locker.unlock();
        if (!found) { return; }
        locker.relock();
        QList<Private::EventSlot> eventSlots;
        eventSlots = d_ptr->events[aEventName];
        locker.unlock();
        for (const auto& eventSlot : std::as_const(eventSlots)) {
            if (!eventSlot.receiver.isNull()) {
                QMetaObject::invokeMethod(eventSlot.receiver,
                    [callback = eventSlot.callback, aEventName, aValue]() {
                    callback(aEventName, aValue);
                }, Qt::QueuedConnection);
            }
        }
        emit eventTriggered(aEventName, aValue);
    }
}

void EventManager::registerEvent(const QString& aEventName, QObject* aReceiver, EventCallback aCallback) noexcept
{
    if (!aEventName.isEmpty() && aReceiver) {
        QMutexLocker locker(&d_ptr->mutex);
        Private::EventSlot eventSlot;
        eventSlot.callback = std::move(aCallback);
        eventSlot.receiver = aReceiver;
        d_ptr->events[aEventName].append(eventSlot);
    }
}

void EventManager::unregisterEvent(const QString &aEventName, QObject *aReceiver) noexcept
{
    if (!aEventName.isEmpty() && aReceiver) {
        QMutexLocker locker(&d_ptr->mutex);
        if (d_ptr->events.contains(aEventName)) {
            auto &eventSlots = d_ptr->events[aEventName];
            eventSlots.erase(std::remove_if(eventSlots.begin(), eventSlots.end(),
                [aReceiver](const Private::EventSlot &slot) {
                    return slot.receiver == aReceiver;
                }), eventSlots.end());
        }
    }
}

EventManager& EventManager::instance() noexcept
{
    static EventManager EventManager;
    return EventManager;
}


Na imagem acima, "ToolBarWidget1" envia um evento para "ZoomIn", e "Drawing Page" escuta esse evento e, ao receber tal evento, reage a ele. Não há problemas, mas assim que preciso, por exemplo, enviar um evento de movimento do mouse da "Drawing page", aparecem travamentos e o programa cai de desempenho. Não é recomendado conectar diretamente a "Drawing page" com módulos, porque dessa forma evitamos a vinculação rígida de módulos. Como isso pode ser otimizado?

PS : 1. Exemplo de envio de um evento:

EventManager::instance().triggerEvent("toolBarWidget1", "zoomIn");

PS : 2. Exemplo de tratamento de eventos:

EventManager::instance().registerEvent("toolBarWidget1",
    this, [this](const QString& eventType, const QVariant& eventValue) {
    (void) eventType;
    if (eventValue.toString() == "zoomIn") { 
        drawingPage->zoomIn(); 
    }
});
c++
  • 1 respostas
  • 73 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve