Бесконечный цикл в QThread
Итак, программа работает с джойстиком, данные с которого выводятся в интерфейс и передаются по Modbus. Для этого получение и обработку данных с джойстика было решено закинуть в отдельный поток. Был оформлен отдельный класс в joyhid.h:
#ifndef JOYHID_H
#define JOYHID_H
#include <QObject>
#include <cstdint>
#include "hidapi.h"
typedef struct _HID_JOYSTK_Info
{
uint16_t X;
uint16_t Y;
uint16_t Z;
uint16_t X_low;
uint16_t Y_low;
uint8_t buttons[5];
}
HID_JOYSTK_Info_TypeDef;
class JoyHID : public QObject
{
Q_OBJECT
public:
explicit JoyHID(QObject *parent = nullptr);
public slots:
void joySlot();
signals:
void joySignal(HID_JOYSTK_Info_TypeDef *obj);
private:
void joyHIDUpdate(HID_JOYSTK_Info_TypeDef *obj);
};
#endif // JOYHID_H
В mainwindow.cpp закидывается в отдельный поток:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QThread *joy_thread = new QThread;
JoyHID *joystck = new JoyHID;
joystck->moveToThread(joy_thread);
connect(joy_thread, SIGNAL(started()), joystck, SLOT(joySlot()));
connect(joystck, &JoyHID::joySignal, this, &MainWindow::uiSlot);
joy_thread->start();
}
В joyhid.cpp слот joySlot() выполняет вот такой незамысловатый код:
void JoyHID::joySlot()
{
joyHIDUpdate(&joyInfo);
emit joySignal(&joyInfo);
}
Отрабатывается одна итерация и я получаю единоразовое обновление значений. Но мне необходимо, чтобы поток крутился постоянно, обновляя значения с джоя. Первой идеей было засунуть в слот joySlot(), например, while(true), но идея потерпела крах. Приложение висло наглухо. Собственно, вопрос, какие работоспособные альтернативы моего решения существуют и что лучше применить в данном случае?
Ответы (2 шт):
Бесконечный цикл while(true) блокирует эвентлуп потока и события/сигналы перестают обрабатываться. Самый простой способ - инициировать обработку событий в вашем цикле:
void JoyHID::joySlot()
{
while(true){
joyHIDUpdate(&joyInfo);
emit joySignal(&joyInfo);
qApp->processEvents();
};
}
или излучить в конце слота повторно сигнал (он встанет в очередь обработки и обработается после всего остального)
joihid.h
class JoyHID : public QObject
{
//.....
signals:
void joySignal(HID_JOYSTK_Info_TypeDef *obj);
void joyWork();
//.....
}
joihid.cpp
JoyHID::JoyHID(QObject *parent)
{
//.....
connect(this, &JoyHID::joyWork, this, &JoyHID::joySlot);
}
void JoyHID::joySlot()
{
joyHIDUpdate(&joyInfo);
emit joySignal(&joyInfo);
emit joyWork();
}
А еще лучше ваш класс представить в виде машины с конечными состояниями (см QStateMachine). Это будет наиболее красиво и правильно
Как альтернативный вариант могу предложить использовать таймер, чтобы сигнал с состоянием джойстика испускался раз в заданный интервал времени. В конструкторе вашего JoyHID примерно так:
timer = new QTimer(this);
timer->setInterval(10); // will emit 100 times per second
connect(timer, &QTimer::timeout, this, &JoyHID::joySlot);
timer->start();
Кстати при таком подходе если метод joySlot нужен только для обслуживания испускания сигнала, его можно заменить на лямбду:
connect(timer, &QTimer::timeout, this, [this]() {
joyHIDUpdate(&joyInfo);
emit joySignal(&joyInfo);
});