У меня есть приложение 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) внутриТема мне кажется очень грязной. Есть ли лучший способ сделать это, у вас есть какие-либо предложения?