Владение Qt Threading - PullRequest
       3

Владение Qt Threading

0 голосов
/ 24 октября 2019

У меня есть приложение Qt, которое подключается к физическим устройствам X через Bluetooth и выполняет некоторый мониторинг. Я хочу иметь своего рода класс ThreadOverseer, который создает поток для каждого устройства для отслеживания по мере необходимости и может воздействовать на сообщения от каждого потока устройства. Я сломал свой стиль кодирования до этого минимального примера:

#include <QCoreApplication>
#include <QList>
#include <QThread>
#include <QObject>
#include <QList>
#include <QDebug>
#include <QTimer>



class DeviceThread : public QThread
{
    Q_OBJECT
public:
    DeviceThread(){}

    void startThread(){this->start(QThread::NormalPriority);}
    void stopThread(){
        m_ping_timer->stop();
        this->quit();
        if (!this->wait(3000)) { this->terminate(); }
    }

    void init(int deviceId){m_deviceId = deviceId;
                           this->moveToThread(this);}

    void run(){
        m_ping_timer = new QTimer(this);
        m_ping_timer->setInterval(5000);
        connect(m_ping_timer, SIGNAL(timeout()), this, SLOT(onPing()));
        m_ping_timer->start();

        this->exec();
    }
private slots:
    void onPing(){
        emit newData(m_deviceId);
    }

signals:
    void newData(int deviceId);
private:
    int m_deviceId;
    QTimer* m_ping_timer;
};

class ThreadOverseer : public QThread
{
    Q_OBJECT
public:
    ThreadOverseer(){}
    void startThread(){
        this->start(QThread::NormalPriority);
    }
    void stopThread(){
        foreach(int deviceId, m_device_threads.keys())
        {
            DeviceThread* thread = m_device_threads.value(deviceId, nullptr);
            if(thread){
                thread->stopThread();
                delete thread;
                thread = nullptr;
            }
        }
    }

    void run()
    {
        foreach(int deviceId, m_deviceIds)
        {
             DeviceThread* dthread = new DeviceThread();
             dthread->init(deviceId);
             connect(dthread, SIGNAL(newData(int)), this, SLOT(onNewDeviceData(int)));
             dthread->startThread();
             m_device_threads.insert(deviceId, dthread);

        }
        this->exec();
    }

    void init(QList<int> deviceIds)
    {
        m_deviceIds = deviceIds;
        this->moveToThread(this);
    }

public slots:
    void onNewDeviceData(int deviceId){
        qDebug() <<  "OVERSEER GOT NEW PING FROM "<< deviceId;
    }

private:
    QList<int> m_deviceIds;
    QMap<int, DeviceThread*> m_device_threads;

};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QList<int> deviceIds;
    deviceIds << 4 << 8 << 42;

    ThreadOverseer* overseer = new ThreadOverseer();
    overseer->init(deviceIds);
    overseer->startThread();

    return a.exec();
}

Я прочитал документацию Qt несколько раз. Похоже, в тех случаях, когда вы хотите парализовать задачи типа «один выстрел», вы создаете QObject, который выполняет необходимые операции, и перемещаете его в QThread (https://doc.qt.io/qt-5/qthread.html#details). В документах также упоминается в случае, если я хочу отправитьданные из ThreadOverseer в слоты в моем deviceThreads подход к рабочему объекту не самый лучший, и подклассы также возможны. Поэтому я создал приведенный выше пример.

Однако это this-> moveToThread (this) внутриТема мне кажется очень грязной. Есть ли лучший способ сделать это, у вас есть какие-либо предложения?

1 Ответ

0 голосов
/ 24 октября 2019

не уверен, что вы подразумеваете под «грязным», но moveToThread () считается полностью жизнеспособным механизмом в QtLand, если вы действительно нуждаетесь в потоках на уровне приложения.

https://doc.qt.io/qt-5/threads-technologies.html обсуждает альтернативы. Я не вижу ничего плохого в вашей реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...