Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Unsolved main and background thread example

    General and Desktop
    3
    20
    6050
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • U
      user4592357 last edited by user4592357

      i wanna write a basic thread example. here's the idea:
      i have the main event loop. before calling app.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 (to join()), so i have a bool 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;
      }
      
      VRonin 1 Reply Last reply Reply Quote 0
      • SGaist
        SGaist Lifetime Qt Champion last edited by

        Hi,

        @user4592357 said in main and background thread example:

        void onMainThreadFinished() {
        bMainThreadRunning = true;
        m_thread.join();
        }

        Shouldn't that be bMainThreadRunning = false; ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply Reply Quote 0
        • U
          user4592357 last edited by

          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.

          1 Reply Last reply Reply Quote 0
          • SGaist
            SGaist Lifetime Qt Champion last edited by

            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.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply Reply Quote 0
            • U
              user4592357 last edited by

              i'll try using QTimer instead of this_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.)?

              1 Reply Last reply Reply Quote 0
              • U
                user4592357 last edited by

                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;
                }
                
                1 Reply Last reply Reply Quote 0
                • SGaist
                  SGaist Lifetime Qt Champion last edited by

                  You forgot you used a std::thread. Why not use QThread since you are using Qt and a worker object ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply Reply Quote 1
                  • U
                    user4592357 last edited by user4592357

                    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 ()
                    
                    1 Reply Last reply Reply Quote 0
                    • SGaist
                      SGaist Lifetime Qt Champion last edited by

                      Did you check the memory used by you application ?

                      Interested in AI ? www.idiap.ch
                      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                      U 1 Reply Last reply Reply Quote 0
                      • U
                        user4592357 @SGaist last edited by user4592357

                        @SGaist

                        what do you mean by check? and no, how should i?

                        1 Reply Last reply Reply Quote 0
                        • SGaist
                          SGaist Lifetime Qt Champion last edited by

                          Using the top command for example. Valgrind etc.

                          Interested in AI ? www.idiap.ch
                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                          U 1 Reply Last reply Reply Quote 1
                          • U
                            user4592357 @SGaist last edited by

                            @SGaist

                            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?

                            1 Reply Last reply Reply Quote 0
                            • SGaist
                              SGaist Lifetime Qt Champion last edited by

                              Yes:
                              QTimer::stop
                              QTimer::start

                              Interested in AI ? www.idiap.ch
                              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                              U 1 Reply Last reply Reply Quote 3
                              • U
                                user4592357 @SGaist last edited by

                                @SGaist

                                hi again,
                                i ran valgrind and it says there's a memory leak on exec() which is in run() overridden method. so what's wrong?

                                1 Reply Last reply Reply Quote 0
                                • VRonin
                                  VRonin @user4592357 last edited by

                                  @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

                                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                  ~Napoleon Bonaparte

                                  On a crusade to banish setIndexWidget() from the holy land of Qt

                                  U 1 Reply Last reply Reply Quote 3
                                  • U
                                    user4592357 @VRonin last edited by

                                    @VRonin

                                    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

                                    1 Reply Last reply Reply Quote 0
                                    • VRonin
                                      VRonin last edited by

                                      https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

                                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                                      ~Napoleon Bonaparte

                                      On a crusade to banish setIndexWidget() from the holy land of Qt

                                      U 1 Reply Last reply Reply Quote 0
                                      • U
                                        user4592357 @VRonin last edited by

                                        @VRonin

                                        i've read similar articles, saying "you shouldn't subclass QThread". in my case i need to do that.

                                        1 Reply Last reply Reply Quote 0
                                        • SGaist
                                          SGaist Lifetime Qt Champion last edited by SGaist

                                          Out of curiosity, what are you doing that requires to subclass QThread ?

                                          Interested in AI ? www.idiap.ch
                                          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                          U 1 Reply Last reply Reply Quote 0
                                          • U
                                            user4592357 @SGaist last edited by

                                            @SGaist

                                            nothing requires it. it's just that the whole implementation is done and i don't wanna change everything

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post