Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to use QThread

How to use QThread

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 5 Posters 675 Views 1 Watching
  • 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.
  • 0 Offline
    0 Offline
    0verEngineer
    wrote on last edited by 0verEngineer
    #1

    I want a Worker class with a QThread that i construct, use and then destruct, i want everything encapsulated in the TaskWorker class (because you cannot have everything in one class if you want to wait for the thread).

    I have following Worker class:

    class Worker : public QObject {
        Q_OBJECT
    
    public:
        Worker() {};
        ~Worker() {};
    
    public slots:
        void process()
        {
            qDebug("Hello World!");
            std::this_thread::sleep_for(std::chrono::seconds(5));
            qDebug("Bye World!");
            emit finished();
        };
    
    signals:
        void finished();
    };
    
    

    And this is the TaskWorker class:

    class TaskWorker : public QObject
    {
        Worker* worker;
        QThread* thread;
    
        Q_OBJECT
    
    public:
        TaskWorker()
        {
            thread = new QThread();
            worker = new Worker();
            worker->moveToThread(thread);
    
            connect(thread, &QThread::started, worker, [=](){worker->process(); qDebug() << "connection 1";});
            connect(worker, &Worker::finished, thread, [=](){thread->quit(); qDebug() << "connection 2";});
            connect(worker, &Worker::finished, worker, [=](){worker->deleteLater(); qDebug() << "connection 3";});
            connect(thread, &QThread::finished, thread, [=](){thread->deleteLater(); qDebug() << "connection 4";});
            thread->start();
        }
    
        ~TaskWorker()
        {
            qDebug() << "~CoolWorker";
            if (thread->isRunning())
            {
                qDebug() << "isRunning";
                thread->quit();
                thread->wait();
            }
    
            delete thread;
            delete worker;
        }
    };
    
    

    Problems:

    1. Closing the App while the process() method is running leads to following output:
    Hello World!
    ~CoolWorker
    isRunning
    Bye World!
    connection 3
    connection 1
    
    Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
    

    The interesting thing is that "connection 1" is printed as last thing, this is connected to QThread::started

    1. Wait for the Process method to finish and then close the app leads to the following:
    Hello World!
    Bye World!
    connection 3
    connection 1
    connection 2
    connection 4
    ~CoolWorker
    
    Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
    
    

    I wan't the app to wait for all threads to finish and then close.

    Thanks a lot for your help :)

    jsulmJ 1 Reply Last reply
    0
    • 0 0verEngineer

      I want a Worker class with a QThread that i construct, use and then destruct, i want everything encapsulated in the TaskWorker class (because you cannot have everything in one class if you want to wait for the thread).

      I have following Worker class:

      class Worker : public QObject {
          Q_OBJECT
      
      public:
          Worker() {};
          ~Worker() {};
      
      public slots:
          void process()
          {
              qDebug("Hello World!");
              std::this_thread::sleep_for(std::chrono::seconds(5));
              qDebug("Bye World!");
              emit finished();
          };
      
      signals:
          void finished();
      };
      
      

      And this is the TaskWorker class:

      class TaskWorker : public QObject
      {
          Worker* worker;
          QThread* thread;
      
          Q_OBJECT
      
      public:
          TaskWorker()
          {
              thread = new QThread();
              worker = new Worker();
              worker->moveToThread(thread);
      
              connect(thread, &QThread::started, worker, [=](){worker->process(); qDebug() << "connection 1";});
              connect(worker, &Worker::finished, thread, [=](){thread->quit(); qDebug() << "connection 2";});
              connect(worker, &Worker::finished, worker, [=](){worker->deleteLater(); qDebug() << "connection 3";});
              connect(thread, &QThread::finished, thread, [=](){thread->deleteLater(); qDebug() << "connection 4";});
              thread->start();
          }
      
          ~TaskWorker()
          {
              qDebug() << "~CoolWorker";
              if (thread->isRunning())
              {
                  qDebug() << "isRunning";
                  thread->quit();
                  thread->wait();
              }
      
              delete thread;
              delete worker;
          }
      };
      
      

      Problems:

      1. Closing the App while the process() method is running leads to following output:
      Hello World!
      ~CoolWorker
      isRunning
      Bye World!
      connection 3
      connection 1
      
      Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
      

      The interesting thing is that "connection 1" is printed as last thing, this is connected to QThread::started

      1. Wait for the Process method to finish and then close the app leads to the following:
      Hello World!
      Bye World!
      connection 3
      connection 1
      connection 2
      connection 4
      ~CoolWorker
      
      Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
      
      

      I wan't the app to wait for all threads to finish and then close.

      Thanks a lot for your help :)

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @0verEngineer said in How to use QThread:

      delete thread;
      delete worker;

      You should use deleteLater()

      thread->deleteLater();
      worker->deleteLater();
      

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      J.HilkJ 1 Reply Last reply
      2
      • jsulmJ jsulm

        @0verEngineer said in How to use QThread:

        delete thread;
        delete worker;

        You should use deleteLater()

        thread->deleteLater();
        worker->deleteLater();
        
        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #3

        @jsulm said in How to use QThread:

        You should use deleteLater()

        @0verEngineer mustn't call delete here, calling delete on a non nullptr already deleted object is UB

        also, don't use this
        std::this_thread::sleep_for(std::chrono::seconds(5));

        to "simulate" work being done it is messing things up. connects etc require the event loop, same as wait() calls


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        0 1 Reply Last reply
        1
        • J.HilkJ J.Hilk

          @jsulm said in How to use QThread:

          You should use deleteLater()

          @0verEngineer mustn't call delete here, calling delete on a non nullptr already deleted object is UB

          also, don't use this
          std::this_thread::sleep_for(std::chrono::seconds(5));

          to "simulate" work being done it is messing things up. connects etc require the event loop, same as wait() calls

          0 Offline
          0 Offline
          0verEngineer
          wrote on last edited by
          #4

          @J-Hilk Hey, thanks a lot for your help, however i removed the delete statements, commented out the work simulation sleep and changed the thread->isRunning check in the destructor.

          The class looks now like that:

          class TaskWorker : public QObject
          {
              Worker* worker;
              QThread* thread;
          
              Q_OBJECT
          
          public:
              TaskWorker()
              {
                  thread = new QThread();
                  worker = new Worker();
                  worker->moveToThread(thread);
          
                  connect(thread, &QThread::started, worker, [=](){worker->process(); qDebug() << "connection 1";});
                  connect(worker, &Worker::finished, thread, [=](){thread->quit(); qDebug() << "connection 2";});
                  connect(worker, &Worker::finished, worker, [=](){worker->deleteLater(); qDebug() << "connection 3";});
                  connect(thread, &QThread::finished, thread, [=](){thread->deleteLater(); qDebug() << "connection 4";});
                  thread->start();
              }
          
              ~TaskWorker()
              {
                  qDebug() << "~CoolWorker";
                  if (thread && thread->isRunning())
                  {
                      qDebug() << "isRunning";
                      thread->quit();
                      thread->wait();
                  }
              }
          };
          
          

          Output on close:

          Hello World!
          Bye World!
          connection 3
          connection 1
          connection 2
          connection 4
          ~CoolWorker
          

          Then it just hangs and does not close

          Remaining Problems:

          1. Why is "connection 1" printed after "Hello World!", "Bye World!" and "connection 3"?

          2. Why does the app not quit this way - it just hangs?

          3. I know that the sleep is blocking the event loop (what i did not know is that wait() need the event loop too) but i mean if i have this worker with a slot doWork() and i start it per signal then the event loop is also blocked until doWork() is finished, so i don't get why the sleep() call to simulate work is a bad thing if the real work is also blocking the event loop?

          JonBJ S 2 Replies Last reply
          0
          • 0 0verEngineer

            @J-Hilk Hey, thanks a lot for your help, however i removed the delete statements, commented out the work simulation sleep and changed the thread->isRunning check in the destructor.

            The class looks now like that:

            class TaskWorker : public QObject
            {
                Worker* worker;
                QThread* thread;
            
                Q_OBJECT
            
            public:
                TaskWorker()
                {
                    thread = new QThread();
                    worker = new Worker();
                    worker->moveToThread(thread);
            
                    connect(thread, &QThread::started, worker, [=](){worker->process(); qDebug() << "connection 1";});
                    connect(worker, &Worker::finished, thread, [=](){thread->quit(); qDebug() << "connection 2";});
                    connect(worker, &Worker::finished, worker, [=](){worker->deleteLater(); qDebug() << "connection 3";});
                    connect(thread, &QThread::finished, thread, [=](){thread->deleteLater(); qDebug() << "connection 4";});
                    thread->start();
                }
            
                ~TaskWorker()
                {
                    qDebug() << "~CoolWorker";
                    if (thread && thread->isRunning())
                    {
                        qDebug() << "isRunning";
                        thread->quit();
                        thread->wait();
                    }
                }
            };
            
            

            Output on close:

            Hello World!
            Bye World!
            connection 3
            connection 1
            connection 2
            connection 4
            ~CoolWorker
            

            Then it just hangs and does not close

            Remaining Problems:

            1. Why is "connection 1" printed after "Hello World!", "Bye World!" and "connection 3"?

            2. Why does the app not quit this way - it just hangs?

            3. I know that the sleep is blocking the event loop (what i did not know is that wait() need the event loop too) but i mean if i have this worker with a slot doWork() and i start it per signal then the event loop is also blocked until doWork() is finished, so i don't get why the sleep() call to simulate work is a bad thing if the real work is also blocking the event loop?

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #5

            @0verEngineer
            Where are you running the Qt event loop? To send signals and for slots to run when cross-thread requires this to process the signals/slots.

            Depending, it is possible that connection 1 would be output earlier if you moved it to before the worker->process() call.

            Why does the app not quit this way - it just hangs?

            You show a thread running to conclusion. You show nothing about the main/UI thread exiting.

            0 1 Reply Last reply
            0
            • JonBJ JonB

              @0verEngineer
              Where are you running the Qt event loop? To send signals and for slots to run when cross-thread requires this to process the signals/slots.

              Depending, it is possible that connection 1 would be output earlier if you moved it to before the worker->process() call.

              Why does the app not quit this way - it just hangs?

              You show a thread running to conclusion. You show nothing about the main/UI thread exiting.

              0 Offline
              0 Offline
              0verEngineer
              wrote on last edited by
              #6

              @JonB OMG, how dumb :D But thats what happens when you try to get stuff working without a pause :D
              I moved the debug outputs before the calls now and the output is now ordered correctly :D

              This is just a Test so i have created a new Test-Project and i have the TestWorker as member in the MainWindow:

              QT_BEGIN_NAMESPACE
              namespace Ui { class MainWindow; }
              QT_END_NAMESPACE
              
              class MainWindow : public QMainWindow
              {
                  Q_OBJECT
              
                  TaskWorker taskWorker;
              
              public:
                  MainWindow(QWidget *parent = nullptr);
                  ~MainWindow();
              
              private:
                  Ui::MainWindow *ui;
              };
              
              
              1 Reply Last reply
              0
              • 0 0verEngineer

                @J-Hilk Hey, thanks a lot for your help, however i removed the delete statements, commented out the work simulation sleep and changed the thread->isRunning check in the destructor.

                The class looks now like that:

                class TaskWorker : public QObject
                {
                    Worker* worker;
                    QThread* thread;
                
                    Q_OBJECT
                
                public:
                    TaskWorker()
                    {
                        thread = new QThread();
                        worker = new Worker();
                        worker->moveToThread(thread);
                
                        connect(thread, &QThread::started, worker, [=](){worker->process(); qDebug() << "connection 1";});
                        connect(worker, &Worker::finished, thread, [=](){thread->quit(); qDebug() << "connection 2";});
                        connect(worker, &Worker::finished, worker, [=](){worker->deleteLater(); qDebug() << "connection 3";});
                        connect(thread, &QThread::finished, thread, [=](){thread->deleteLater(); qDebug() << "connection 4";});
                        thread->start();
                    }
                
                    ~TaskWorker()
                    {
                        qDebug() << "~CoolWorker";
                        if (thread && thread->isRunning())
                        {
                            qDebug() << "isRunning";
                            thread->quit();
                            thread->wait();
                        }
                    }
                };
                
                

                Output on close:

                Hello World!
                Bye World!
                connection 3
                connection 1
                connection 2
                connection 4
                ~CoolWorker
                

                Then it just hangs and does not close

                Remaining Problems:

                1. Why is "connection 1" printed after "Hello World!", "Bye World!" and "connection 3"?

                2. Why does the app not quit this way - it just hangs?

                3. I know that the sleep is blocking the event loop (what i did not know is that wait() need the event loop too) but i mean if i have this worker with a slot doWork() and i start it per signal then the event loop is also blocked until doWork() is finished, so i don't get why the sleep() call to simulate work is a bad thing if the real work is also blocking the event loop?

                S Offline
                S Offline
                SimonSchroeder
                wrote on last edited by
                #7

                @0verEngineer said in How to use QThread:

                Why is "connection 1" printed after "Hello World!", "Bye World!" and "connection 3"?

                You write that it should first do process() and only after that print "connection 1". process() itself prints "Hello World!" and "Bye World!". After that it emits finished() which will most likely be a direct connection by default because it is all within the same thread. This means that immediately the slot for WorkerThread::finished will be executed and print "connection 3". Now, process() returns and only then "connection 1" can be printed. "connection 2" is printed later because thread is in a different thread than worker. This makes it a queued connection and thus could be executed in any order.

                1 Reply Last reply
                1

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved