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. Best QThread practices

Best QThread practices

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 7 Posters 413 Views
  • 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.
  • Christian EhrlicherC Offline
    Christian EhrlicherC Offline
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on last edited by
    #3

    The second one will not work as 'timer' lives in the main thread

    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
    Visit the Qt Academy at https://academy.qt.io/catalog

    1 Reply Last reply
    3
    • jsulmJ jsulm

      @DalePennington I would suggest a third approach: worker object. This way there is no need to subclass QThread.
      See example here: https://doc.qt.io/qt-6/qthread.html

      D Offline
      D Offline
      DalePennington
      wrote on last edited by
      #4

      @jsulm I was not looking at worker object first, because it seemed to add complications. Also it looks like doWork is called once, and keeps running to completion, so no time outs for any for event processing. Note that this thread would basically run from app start to app shutdown. So how could such an object for example receive an incoming signal ?

      Dale

      JoeCFDJ 1 Reply Last reply
      0
      • D DalePennington

        @jsulm I was not looking at worker object first, because it seemed to add complications. Also it looks like doWork is called once, and keeps running to completion, so no time outs for any for event processing. Note that this thread would basically run from app start to app shutdown. So how could such an object for example receive an incoming signal ?

        Dale

        JoeCFDJ Offline
        JoeCFDJ Offline
        JoeCFD
        wrote on last edited by
        #5

        @DalePennington worker is an object. Connect worker with any widget or object which sends signals to worker.

        1 Reply Last reply
        0
        • D Offline
          D Offline
          DalePennington
          wrote on last edited by
          #6

          I am clearly missing something about how the worker object really works. The example in the QThread documentation is incomplete. But it looks to me like the doWork, when kicked off, runs during completion, not performing a slice of work. I assume while doWork is executing, there is not event processing occuring on that thread, so no events delivered.

          Pl45m4P JonBJ 2 Replies Last reply
          0
          • D DalePennington

            I am clearly missing something about how the worker object really works. The example in the QThread documentation is incomplete. But it looks to me like the doWork, when kicked off, runs during completion, not performing a slice of work. I assume while doWork is executing, there is not event processing occuring on that thread, so no events delivered.

            Pl45m4P Offline
            Pl45m4P Offline
            Pl45m4
            wrote on last edited by
            #7

            @DalePennington

            Compare this table to your needs:

            • https://doc.qt.io/qt-6/threads-technologies.html#example-use-cases

            A worker QObject can be controlled using signals that you emit from your main thread or object. In the same way you can get data back or even stop/restart your worker.


            If debugging is the process of removing software bugs, then programming must be the process of putting them in.

            ~E. W. Dijkstra

            1 Reply Last reply
            0
            • D DalePennington

              I am clearly missing something about how the worker object really works. The example in the QThread documentation is incomplete. But it looks to me like the doWork, when kicked off, runs during completion, not performing a slice of work. I assume while doWork is executing, there is not event processing occuring on that thread, so no events delivered.

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

              @DalePennington said in Best QThread practices:

              But it looks to me like the doWork, when kicked off, runs during completion, not performing a slice of work. I assume while doWork is executing, there is not event processing occuring on that thread, so no events delivered.

              Correct.

              Unless you do some explicit processEvents() yourself in the thread, which is no more advisable than doing so in the main thread event loop. Just saying for completeness.

              1 Reply Last reply
              0
              • D Offline
                D Offline
                DalePennington
                wrote on last edited by DalePennington
                #9

                OK, I see the table saying use a worker object, but then JonB says that when doWork is running, I cannot get signals into the thread for processing. I assume signals can go out, but how do I get them in (for example, having a controlled shutdown on work rather than just quiting under it). Do I just have to treat it like a stock unix thread and have QMutexes and QWaitConditions around booleans to communcate into the processing thread ?

                As a follow-on I now have worker pattern working. I did this by having doWork just initialize what I need and then use QTimers and Slots to cause breaks for events to show up. I am still having an issue on how to clean up when the main window is closed. I emit a signal to the worker but it does not get processed before the app shuts down. Since I want the cleanup to process within the context of the worker thread, how do I get it to cleanup on program exit ?

                Thanks for the time
                Dale

                Pl45m4P 1 Reply Last reply
                0
                • D DalePennington

                  OK, I see the table saying use a worker object, but then JonB says that when doWork is running, I cannot get signals into the thread for processing. I assume signals can go out, but how do I get them in (for example, having a controlled shutdown on work rather than just quiting under it). Do I just have to treat it like a stock unix thread and have QMutexes and QWaitConditions around booleans to communcate into the processing thread ?

                  As a follow-on I now have worker pattern working. I did this by having doWork just initialize what I need and then use QTimers and Slots to cause breaks for events to show up. I am still having an issue on how to clean up when the main window is closed. I emit a signal to the worker but it does not get processed before the app shuts down. Since I want the cleanup to process within the context of the worker thread, how do I get it to cleanup on program exit ?

                  Thanks for the time
                  Dale

                  Pl45m4P Offline
                  Pl45m4P Offline
                  Pl45m4
                  wrote on last edited by Pl45m4
                  #10

                  @DalePennington said in Best QThread practices:

                  As a follow-on I now have worker pattern working. I did this by having doWork just initialize what I need and then use QTimers and Slots to cause breaks for events to show up.

                  No!
                  You don't need timers to "interrupt" your process.

                  • https://wiki.qt.io/QThreads_general_usage

                  As far as I understand your initial idea of parsing/writing log files, you can create your object, let's say "LogFileWorker", and start it while passing a filename for example with a start(filename) signal connected to the worker slot which processes the file.
                  Once the worker is finished (or even in between) you can send results/signals to the main thread.
                  This whole procedure can be repeated whenever you want to and wherever you call worker->start (or whatever you call your signal/function to init the start of your worker/thread).

                  The main difference to your QThread::run() approach is that you do receive signals via your QObject worker that lives in a plain and simple QThread ( Qt's thread wrapper class), which in turn does not require any further configurations.

                  Edit:
                  In regards to proper cleanup, also read the article I've linked above in this post here
                  (it's also done through utilization of cross-thread signals calling QObject::deleteLater for example)


                  If debugging is the process of removing software bugs, then programming must be the process of putting them in.

                  ~E. W. Dijkstra

                  1 Reply Last reply
                  0
                  • D Offline
                    D Offline
                    DalePennington
                    wrote on last edited by
                    #11

                    Actually what each thread is doing is getting input from a socket via a third party library (each thread is one "channel" which it its own socket). For now we are logging the data in a file, but later will be parsing some data and passing it along elsewhere in the app. So the thread runs constantly from start till the app is shut down.

                    Without the timer breakup, the process thread would never get any slots invoked as it would never give up processing in the thread. Also the cleanup issue I am concerned with is when the operator closes the app (for example via hitting the X button in the upper right corner). At that point I want each thread to close its log file so no data is lost. Since the app is being exited the deleteLater never occurs so the destructor is not called, so that is not a valid cleanup method (I put some debug prints to make sure this is the case).

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      SimonSchroeder
                      wrote on last edited by
                      #12

                      I would say that initially you weren't fully on the wrong track. You just need to move everything out of QThread and into a worker object. If you are lazy it could even be just separate lambdas:

                      QThread *thread = new QThread();
                      connect(thread, &QThread::startet, []() { /* initialize */ });
                      connect(thread, &QThread::finished, []() { /* cleanup */ });
                      connect(thread, &QThread::finished, thread, &QThread::deleteLater);
                      QMetaObject::invokeMethod(thread, []() { /* do work */ });
                      thread->start();
                      

                      Notice the use of QMetaObject::invokeMethod to explicitly put a function call into the event loop of the thread. Using a worker object with slots instead of the lambdas is the cleaner approach.

                      What you should never do is have an infinite loop for processing. Usually, there should be a trigger (i.e. a signal) to do another round of processing. However, sometimes you need to poll information in which case the timer could be a right choice. There is a trick with using a QTimer with timeout of 0 ms. This means that whenever the thread is idle the timer will timout. Note that "whenever the thread is idle" also means that one CPU core will be fully utilized constantly. Having a timeout of a few milliseconds can reduce that.

                      Another way with a worker object (which would also use up one CPU core) would be the following: Suppose you have a signal WorkerObject::triggerProcessing() which is connected to a slot WorkerObject::process(). Instead of

                      void WorkerObject::process()
                      {
                          while(!done)
                          {
                              // do work
                          }
                      }
                      

                      you can do this:

                      void WorkerObject::process()
                      {
                          if(!done)
                          {
                              // do work
                              if(!done) //still not done
                                  emit triggerProcessing(); // do another round of processing
                          }
                      }
                      

                      In this case you would launch the first round of processing using QMetaObject::invokeMethod on WorkerObject::process.

                      Without knowing what you want to achieve it is hard to tell which approach would be most appropriate in your case. The most important thing, though, is: Don't use an infinite loop (with a break condition) inside a running event loop.

                      1 Reply Last reply
                      0
                      • D Offline
                        D Offline
                        DalePennington
                        wrote on last edited by
                        #13

                        That is basically the approach I am using. Only with a short timer to give up the core for a little bit. Messages average about 1/sec, but we want quick response as part of this effort is to do some timing analysis before creating the final app.

                        I had looked at finish early on as an early approach, but at that point I was looking for an "in-thread" use with a subclassed QThread, and the slot invocations in that case were in the parent thread, not wanted. However, using the Worker pattern, when the finished signal function is called, it is even in the worker thread, which appears to solve my problem for now.

                        Thanks,
                        Dale

                        1 Reply Last reply
                        0
                        • D DalePennington has marked this topic as solved on

                        • Login

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