main and background thread example
-
i wanna write a basic thread example. here's the idea:
i have the main event loop. before callingapp.exec()
, i create an object which itself creates an object and puts it in a separate thread for running. i need some way to tell the background thread that main thread has finished (tojoin()
), so i have abool
to indicate that.however, when the application exits, something goes wrong. i'm running it using visual studio and the debugging session won't stop. i don't understand what's wrong. here's the code:
#include <QApplication> #include <QObject> #include <QThread> #include <iostream> #include <thread> #include <QtWidgets/QLabel> #include <atomic> std::atomic<bool> bMainThreadRunning { true }; class ThreadObj { public: void work() { while(bMainThreadRunning) { ++counter; std::this_thread::sleep_for(std::chrono::seconds(5)); } } private: int counter { 0 }; }; class Obj { public: void start() { ThreadObj obj; m_thread = std::thread(&ThreadObj::work, &obj); } void onMainThreadFinished() { bMainThreadRunning = true; m_thread.join(); } private: std::thread m_thread; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); Obj o; o.start(); QWidget w; w.show(); auto ret = a.exec(); o.onMainThreadFinished(); return 0; }
-
Hi,
@user4592357 said in main and background thread example:
void onMainThreadFinished() {
bMainThreadRunning = true;
m_thread.join();
}Shouldn't that be
bMainThreadRunning = false;
? -
my bad, that's right, i tried to implement what's in my actual project in a snippet and that's what i got automatically.
but anyways that's not the result i expect. what i expect is, when the main thread finishes i need the background thread to be notified and finish immediately, but with this code it was for the interval to exit.
actually in my actual project i implemented that scenario, it's basically the same code but then i had to change the places where all of these objects are created and this is the result i get. -
Well, if you thread just started to sleep, you'll have to wait for your 5 seconds before it ends properly.
Do you really have that kind of loop in your application ? It could be reworked to use e.g. a QTimer in a worker object.
-
i'll try using
QTimer
instead ofthis_thread::sleep_for()
. but it still blows my mind how my previous implementation worked the way i wanted with this code.and is everything else okay with this code (i.e. the use of atomic bool etc.)?
-
i can't figure out how to do that. this is what i have right now:
#include <QtWidgets/QMainWindow> #include <QApplication> #include <QObject> #include <QThread> #include <iostream> #include <thread> #include <QtWidgets/QLabel> #include <atomic> #include <QTimer> std::atomic<bool> bMainThreadRunning { true }; class ThreadObj : public QObject { public: ThreadObj() : counter(0) {} void work() { auto timer = new QTimer; //timer.setInterval(3000); connect(timer, &QTimer::timeout, this, &ThreadObj::inc); timer->start(3000); } void inc() { while(bMainThreadRunning) ++counter; } private: int counter { 0 }; }; class Obj { public: void start() { ThreadObj obj; m_thread = std::thread(&ThreadObj::work, &obj); } void onMainThreadFinished() { bMainThreadRunning = false; m_thread.join(); } private: std::thread m_thread; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); Obj o; o.start(); QWidget w; w.show(); auto ret = a.exec(); o.onMainThreadFinished(); return 0; }
-
i did that. what i need is, when in background thread something weird happens, i tell the main thread to show a message box. then if at some time the "good" state of background thread is restored, main thread closes the message box.
here's what i have now. actually the application works. but at some points it crashes. looking at the crash log i can say that the reason is the background thread but i don't see how my implementation is wrong. i appended the crash log after code.
class BgThread : public QThread { Q_OBJECT public: explicit BgThread (const int &nSeconds, QObject *parent = nullptr) : QThread(parent), interval(1000 * nSeconds) /* to milliseconds */ {} void onStopBgThread() { running = false; } signals: void somethingWentWrong(); void restoreGoodState(); private slots: void performWork() { if(/* something went wrong */) { emit somethingWentWrong(); good_state = false; } else if(!good_state) { // means going from bad state to good state emit restoreGoodState(); good_state = true; } } private: void run() override { QTimer timer; connect(&timer, SIGNAL(timeout()), this, SLOT(performWork()), Qt::DirectConnection); timer.start(interval); exec(); quit(); wait(); } private: int interval; bool running { true }; bool good_state { true }; }; class MainApp { public: void start_bg_thread(const int seconds) { thread = new BgThread { seconds, this }; connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); connect(thread, SIGNAL(somethingWentWrong()), SLOT(onSomethingWentWrong())); connect(thread, SIGNAL(restoreGoodState()), SLOT(onRestoreGoodState())); thread->start(); } void stop_bg_thread() { thread->onStopBgThread(); } public slots: void onSomethingWentWrong() { if(!msgBox) { msgBox= new QMessageBox(window()); msgBox->setIcon(QMessageBox::Warning); msgBox->setWindowTitle("window title"); msgBox->setText("message box text"); const auto pExitBtn = msgBox->addButton(tr("Exit"), QMessageBox::AcceptRole); connect(pExitBtn, SIGNAL(clicked()), qApp, SLOT(quit())); } msgBox->exec(); } void onRestoreGoodState() { msgBox->close(); } private: BgThread *thread { nullptr }; QMessageBox *msgBox; };
this is basically it. and somewhere in the app init process i call
MainApp app; app.start_bg_thread(5);
the crash log is something like this (stacktrace):
do_system () from /lib64/libc.so.6 system () from /lib64/libc.so.6 // call signal handler ... pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0 QThread::msleep(unsigned long) () start_thread () from /lib64/libpthread.so.0 clone () from /lib64/libc.so.6 waitpid () from /lib64/libc.so.6 do_system () from /lib64/libc.so.6 system () from /lib64/libc.so.6 // call signal handler BgThread::onStopBgThread () MainApp::qt_metacall(QMetaObject::Call, int, void**) () QMetaObject::activate(QObject*, QMetaObject const*, int, void**) () QCoreApplication::exec() main ()
-
Did you check the memory used by you application ?
-
Using the top command for example. Valgrind etc.
-
-
@user4592357 said in main and background thread example:
ThreadObj obj;
m_thread = std::thread(&ThreadObj::work, &obj);obj is allocated on the stack, it will go out of scope and delete itself
-
Out of curiosity, what are you doing that requires to subclass QThread ?