Nested QFuture - выпуск QtConcurrent
У меня такая ситуация: мне нужно постоянно обновлять некоторые метки интерфейса со значениями, которые я читаю с некоторых датчиков SPI, без блокировки интерфейса. Код практически идентичен для каждого датчика и выглядит так:
double SPIHandler::scaleGetQuickWeight(){
double weightValue = SCALE_ERROR_VALUE;
QElapsedTimer *timer = new QElapsedTimer();
timer->start();
QFuture<double> future = QtConcurrent::run(&SPIHandler::thread_scaleGetWeight);
while(timer->elapsed() < 5000){
if (future.isFinished()){
future.end();
weightValue = future.result();
return weightValue;
}
}
//when called by the functions I posted below, the program always ends here
future.cancel();
myParent->log("Malfunctioning scale", MainWindow::LOG_ERROR);
return SCALE_ERROR_VALUE;
}
double SPIHandler::thread_scaleGetWeight(){
float val;
//myParent->log("check");
if (scale_read_value(fd_scale, &val) == 0){
return ftod(convertReadingsIntoWeight(val, k_cal, q_cal)*1000);
} else {
myParent->log("Malfunctioning scale in QtConcurrent", MainWindow::LOG_ERROR);
return SCALE_ERROR_VALUE;
}
}
Для каждого датчика у меня есть поток, запущенный вызовом QtConcurrent::run(), который я прекращаю, если через 5 секунд он не дает результата: эти части кода работают отлично, когда используются в другом месте. Проблема возникает, когда я пытаюсь вызвать функцию, которая содержит вызов QtConcurrent::run() из другого потока, который, в свою очередь, был создан другим QtConcurrent::run(), запущенным по таймауту QTimer. Соответствующий код в QWidget, который нуждается в обновлении меток, таков:
DiagnosticWindow::DiagnosticWindow(QWidget *parent) :
QTabWidget(parent),
ui(new Ui::DiagnosticWindow)
{
[...]
//connect to make sure that timer is running only when the right tab is selected
connect(this, SIGNAL(currentChanged(int)), this, SLOT(on_diagnosticWindow_currentChanged(int)));
//setting up timer
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(on_timer_timeout()));
///setting up QFutureWatcher
watcher = new QFutureWatcher<void>();
connect(watcher, SIGNAL(finished()), this, SLOT(updateGraphics()));
[...]
}
void DiagnosticWindow::on_diagnosticWindow_currentChanged(int index)
{
//slot to start timer when tab 2 is selected
if (index == 2){
[...]
timer->setSingleShot(false);
timer->start(750);
} else{
printf("timer stopped\r\n");
timer->stop();
[...]
}
}
void DiagnosticWindow::on_timer_timeout(){
//slot to start QtConcurrent on timer timeout
QFuture<void> future = QtConcurrent::run(&diagnosticWindow::updateValues);
watcher->setFuture(future);
}
void DiagnosticWindow::updateValues(){
//function run by QFuture: I didn't post the code of these functions,
//but each one simply calls the respective function written like the one
//posted above
weight = myParent->deviceScaleGetQuickWeight();
temperature = myParent->devicePressGetValue();
pressure = myParent->deviceTempGetValue();
}
void DiagnosticWindow::updateGraphics(){
//slot called when QFutureWatcher signals isFinished()
ui->lbl_peso->setText(QString("%1").arg(weight));
ui->lbl_pressione->setText(QString("%1").arg(pressure));
ui->lbl_temperatura->setText(QString("%1").arg(temperature));
}
Итак, подведем итог, это должно быть поведение:
вкладка выбирается -> запускается таймер -> останавливается таймер -> запускается QFuture 1 и, в свою очередь, вызывает другой QFuture 2 -> заканчивается QFuture 2 -> заканчивается QFuture 1 -> обновляется пользовательский интерфейс
и это работает таким образом, но это всегда дает мне ошибку сбоя. QFuture 1 работает, потому что через 5 секунд я получаю сообщение о неисправности, поэтому мне кажется, что QFuture 2 никогда не вызывает функцию. Я попытался добавить, что прокомментировал "myParent->log("check");" к функции, вызываемой QFuture 2, чтобы иметь доказательство того, что функция была вызвана, но в этом случае я никогда не получаю это сообщение журнала (но я получаю его, когда читаю с датчика в других частях кода).
Вопрос в том, может ли что-то в приведенном выше коде объяснить такое поведение? Я что-то упускаю? Я могу добавить больше кода, если это необходимо, но, поскольку я могу правильно читать значения датчиков даже из того же класса DiagnosticWindow, я не думаю, что это могло бы помочь. Спасибо, парни