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 ?
-
what do you mean by check? and no, how should i?
-
Using the top command for example. Valgrind etc.
-
okay, thanks.
one last question, as you can see, on timer's timeout i execute a function. is it possible stop the timer (so the function won't be executed), and then restart it again? -
-
hi again,
i ran valgrind and it says there's a memory leak onexec()
which is inrun()
overridden method. so what's wrong? -
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; }
@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
-
@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
hi, thanks for the reply.
the code has been modified since the first post (see my last code-post), so it's not the problem -
i've read similar articles, saying "you shouldn't subclass
QThread
". in my case i need to do that. -
Out of curiosity, what are you doing that requires to subclass QThread ?
-
nothing requires it. it's just that the whole implementation is done and i don't wanna change everything