From 546b023dbc0c19f8771a0329656ef5d8c524c77f Mon Sep 17 00:00:00 2001 From: Nova Date: Wed, 22 Oct 2025 03:22:24 +0330 Subject: [PATCH] Fix threading issues --- include/global/Utils.hpp | 6 ++-- src/global/Utils.cpp | 58 ++++++++++++++++++++++++++++++++++---- src/sys/Process.cpp | 5 +++- src/ui/mainwindow_grpc.cpp | 5 +++- 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/include/global/Utils.hpp b/include/global/Utils.hpp index 28fc945..1cd45e4 100644 --- a/include/global/Utils.hpp +++ b/include/global/Utils.hpp @@ -167,11 +167,11 @@ void ActivateWindow(QWidget *w); // -void runOnUiThread(const std::function &callback); +void runOnUiThread(const std::function &callback, bool wait = false); -void runOnNewThread(const std::function &callback); +void runOnNewThread(const std::function &callback, bool wait = false); -void runOnThread(const std::function &callback, QObject *parent); +void runOnThread(const std::function &callback, QObject *parent, bool wait = false); template inline void connectOnce(EMITTER *emitter, SIGNAL signal, RECEIVER *receiver, ReceiverFunc f, diff --git a/src/global/Utils.cpp b/src/global/Utils.cpp index 45504d2..d7a2ea8 100644 --- a/src/global/Utils.cpp +++ b/src/global/Utils.cpp @@ -249,38 +249,84 @@ void ActivateWindow(QWidget *w) { w->activateWindow(); } -void runOnUiThread(const std::function &callback) { +void runOnUiThread(const std::function &callback, bool wait) { // any thread auto *timer = new QTimer(); auto thread = mainwindow->thread(); timer->moveToThread(thread); timer->setSingleShot(true); - QObject::connect(timer, &QTimer::timeout, [=]() { + + QEventLoop loop; + QObject::connect(timer, &QTimer::timeout, [=, &loop]() { // main thread callback(); timer->deleteLater(); + + if (wait) + { + QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection); + } }); QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0)); + + if (wait && QThread::currentThread() != thread) { + loop.exec(); + } } -void runOnNewThread(const std::function &callback) { - createQThread(callback)->start(); +void runOnNewThread(const std::function &callback, bool wait) { + auto *timer = new QTimer(); + auto thread = new QThread(); + timer->moveToThread(thread); + timer->setSingleShot(true); + + thread->start(); + QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater); + + QEventLoop loop; + QObject::connect(timer, &QTimer::timeout, [=, &loop]() { + callback(); + timer->deleteLater(); + QMetaObject::invokeMethod(thread, "quit", Qt::QueuedConnection); + + if (wait) + { + QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection); + } + }); + QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0)); + + if (wait && QThread::currentThread() != thread) { + loop.exec(); + } } -void runOnThread(const std::function &callback, QObject *parent) { +void runOnThread(const std::function &callback, QObject *parent, bool wait) { auto *timer = new QTimer(); auto thread = dynamic_cast(parent); if (thread == nullptr) { timer->moveToThread(parent->thread()); + thread = parent->thread(); } else { timer->moveToThread(thread); } timer->setSingleShot(true); - QObject::connect(timer, &QTimer::timeout, [=]() { + + QEventLoop loop; + QObject::connect(timer, &QTimer::timeout, [=, &loop]() { callback(); timer->deleteLater(); + + if (wait) + { + QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection); + } }); QMetaObject::invokeMethod(timer, "start", Qt::QueuedConnection, Q_ARG(int, 0)); + + if (wait && QThread::currentThread() != thread) { + loop.exec(); + } } void setTimeout(const std::function &callback, QObject *obj, int timeout) { diff --git a/src/sys/Process.cpp b/src/sys/Process.cpp index 2c3238a..c931e1c 100644 --- a/src/sys/Process.cpp +++ b/src/sys/Process.cpp @@ -62,7 +62,10 @@ namespace Configs_sys { if (restarting) return; MW_show_log("[Fatal] " + QObject::tr("Core exited, cleaning up...")); - GetMainWindow()->profile_stop(true, true); + runOnUiThread([=, this] + { + GetMainWindow()->profile_stop(true, true); + }, true); // Retry rate limit if (coreRestartTimer.isValid()) { diff --git a/src/ui/mainwindow_grpc.cpp b/src/ui/mainwindow_grpc.cpp index bb072de..6a3b191 100644 --- a/src/ui/mainwindow_grpc.cpp +++ b/src/ui/mainwindow_grpc.cpp @@ -570,7 +570,10 @@ void MainWindow::profile_start(int _id) { runOnNewThread([=, this] { // stop current running if (running != nullptr) { - profile_stop(false, true, true); + runOnUiThread([=, this] + { + profile_stop(false, true, true); + }, true); } // do start MW_show_log(">>>>>>>> " + tr("Starting profile %1").arg(ent->bean->DisplayTypeAndName()));