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
QtWS25 Last Chance

Best QThread practices

Scheduled Pinned Locked Moved Solved General and Desktop
13 Posts 7 Posters 383 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.
  • 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