From 1ddff3c2a4efe4bfcc24619d7646ec0abc06cc0c Mon Sep 17 00:00:00 2001 From: Nav Date: Thu, 8 Sep 2022 16:07:22 +0100 Subject: [PATCH] Support for multiple InsightWorker threads. We now have three InsightWorker threads as opposed to one --- README.md | 2 +- src/Insight/Insight.cpp | 52 +++++++++++++-------- src/Insight/Insight.hpp | 15 +++--- src/Insight/InsightWorker/InsightWorker.cpp | 2 - 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 5d11d7b7..36f7d7fa 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Bloom and thus the connected AVR target. The DebugServer runs on a dedicated thr ##### Insight Insight is a graphical user interface that provides insight into the connected target. It presents the target's memories, GPIO pin states & registers, along with the ability to manipulate them. Insight occupies Bloom's main thread -and employs a single worker thread for background tasks. Unlike other components within Bloom, Insight relies heavily +and employs several worker threads for background tasks. Unlike other components within Bloom, Insight relies heavily on the Qt framework for its GUI capabilities and other useful utilities. See source code in src/Insight/ for more. ##### SignalHandler diff --git a/src/Insight/Insight.cpp b/src/Insight/Insight.cpp index 993fc10f..ac213551 100644 --- a/src/Insight/Insight.cpp +++ b/src/Insight/Insight.cpp @@ -45,7 +45,6 @@ namespace Bloom try { this->startup(); - this->workerThread->start(); this->setThreadState(ThreadState::READY); Logger::info("Insight ready"); this->application.exec(); @@ -179,20 +178,31 @@ namespace Bloom this->mainWindow->setInsightConfig(this->insightConfig); this->mainWindow->setEnvironmentConfig(this->environmentConfig); - // Prepare worker thread - this->workerThread = new QThread(); - this->workerThread->setObjectName("IW" + QString::number(this->insightWorker->id)); - this->insightWorker->moveToThread(this->workerThread); - QObject::connect(this->workerThread, &QThread::started, this->insightWorker, &InsightWorker::startup); - QObject::connect(this->workerThread, &QThread::finished, this->insightWorker, &QObject::deleteLater); - QObject::connect(this->workerThread, &QThread::finished, this->workerThread, &QThread::deleteLater); + // Construct and start worker threads + for (std::uint8_t i = 0; i < Insight::INSIGHT_WORKER_COUNT; ++i) { + auto* insightWorker = new InsightWorker(); + auto* workerThread = new QThread(); + + workerThread->setObjectName("IW" + QString::number(insightWorker->id)); + insightWorker->moveToThread(workerThread); + QObject::connect(workerThread, &QThread::started, insightWorker, &InsightWorker::startup); + QObject::connect(workerThread, &QThread::finished, insightWorker, &QObject::deleteLater); + QObject::connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); + + this->insightWorkersById[insightWorker->id] = std::pair(insightWorker, workerThread); + + // TODO: Remove this hack. Find a better way to trigger the latest version check. + if (i == 0) { + QObject::connect(insightWorker, &InsightWorker::ready, this, [this] { + this->checkBloomVersion(); + }); + } + + Logger::debug("Starting InsightWorker" + std::to_string(insightWorker->id) + " thread"); + workerThread->start(); + } this->mainWindow->init(this->targetControllerConsole.getTargetDescriptor()); - - QObject::connect(this->insightWorker, &InsightWorker::ready, this, [this] { - this->checkBloomVersion(); - }); - this->mainWindow->show(); } @@ -205,11 +215,15 @@ namespace Bloom this->mainWindow->close(); - if (this->workerThread != nullptr && this->workerThread->isRunning()) { - Logger::debug("Stopping InsightWorker thread"); - this->workerThread->quit(); - Logger::debug("Waiting for InsightWorker thread to stop"); - this->workerThread->wait(); + for (auto& [workerId, workerPair] : this->insightWorkersById) { + auto* workerThread = workerPair.second; + + if (workerThread != nullptr && workerThread->isRunning()) { + Logger::debug("Stopping InsightWorker" + std::to_string(workerId) + " thread"); + workerThread->quit(); + Logger::debug("Waiting for InsightWorker" + std::to_string(workerId) + " thread to stop"); + workerThread->wait(); + } } this->application.exit(0); @@ -237,7 +251,7 @@ namespace Bloom } ); - this->insightWorker->queueTask(versionQueryTask); + InsightWorker::queueTask(versionQueryTask); } void Insight::onInsightWindowActivated() { diff --git a/src/Insight/Insight.hpp b/src/Insight/Insight.hpp index 17e55906..bae21b00 100644 --- a/src/Insight/Insight.hpp +++ b/src/Insight/Insight.hpp @@ -2,6 +2,10 @@ #include #include +#include +#include +#include +#include #include "src/Helpers/Thread.hpp" #include "src/Helpers/Paths.hpp" @@ -62,6 +66,7 @@ namespace Bloom void shutdown(); private: + static constexpr std::uint8_t INSIGHT_WORKER_COUNT = 3; std::string qtApplicationName = "Bloom"; std::array qtApplicationArgv = {this->qtApplicationName.data()}; int qtApplicationArgc = 1; @@ -75,7 +80,9 @@ namespace Bloom EventListener& eventListener; QApplication application; - InsightWorker* insightWorker = new InsightWorker(); + + std::map> insightWorkersById; + InsightWindow* mainWindow = new InsightWindow( this->environmentConfig, this->insightConfig, @@ -86,12 +93,6 @@ namespace Bloom Targets::TargetState lastTargetState = Targets::TargetState::UNKNOWN; InsightSignals* insightSignals = InsightSignals::instance(); - /** - * Insight consists of two threads - the main thread where the main Qt event loop runs (for the GUI), and - * a single worker thread to handle any blocking/time-expensive operations. - */ - QThread* workerThread = nullptr; - void startup(); /** diff --git a/src/Insight/InsightWorker/InsightWorker.cpp b/src/Insight/InsightWorker/InsightWorker.cpp index f93b41b3..d57aa704 100644 --- a/src/Insight/InsightWorker/InsightWorker.cpp +++ b/src/Insight/InsightWorker/InsightWorker.cpp @@ -12,8 +12,6 @@ namespace Bloom using Bloom::Targets::TargetState; void InsightWorker::startup() { - Logger::debug("Starting InsightWorker" + std::to_string(this->id) + " thread"); - QObject::connect( InsightSignals::instance(), &InsightSignals::taskQueued,