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. Is using QTimer:: singlehot a good way to modify objects in other threads?
QtWS25 Last Chance

Is using QTimer:: singlehot a good way to modify objects in other threads?

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 8 Posters 660 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.
  • J Offline
    J Offline
    John Van
    wrote on last edited by
    #1

    For example, if I want to modify the text of the label in the background thread, I can use QTimer:: singlehot (0, label, [=] () {label ->setText ("abc");}) in program;

    jsulmJ JonBJ 2 Replies Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      I don't see any overloads for QTimer to use QeuedConnection type. And in any case, you're using a lambda so it will be called in the same thread. So, the answer seems to be "no".

      (Z(:^

      JKSHJ 1 Reply Last reply
      0
      • J John Van

        For example, if I want to modify the text of the label in the background thread, I can use QTimer:: singlehot (0, label, [=] () {label ->setText ("abc");}) in program;

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

        @John-Van Why not simply emit a signal to trigger text modification in the UI thread?

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

        1 Reply Last reply
        2
        • sierdzioS sierdzio

          I don't see any overloads for QTimer to use QeuedConnection type. And in any case, you're using a lambda so it will be called in the same thread. So, the answer seems to be "no".

          JKSHJ Offline
          JKSHJ Offline
          JKSH
          Moderators
          wrote on last edited by
          #4

          @sierdzio said in Is using QTimer:: singlehot a good way to modify objects in other threads?:

          I don't see any overloads for QTimer to use QeuedConnection type. And in any case, you're using a lambda so it will be called in the same thread. So, the answer seems to be "no".

          The "context" object (which @John-Van provided) determines which thread the lambda will run in. It also activates Qt::QueuedConnection if the timer and the context object live in different threads. So, @John-Van's code will work fine.

          Having said that, QMetaObject::invokeMethod() is a bit more intuitive than QTimer::singleShot(): https://doc.qt.io/qt-6/qmetaobject.html#invokeMethod-8

          Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

          1 Reply Last reply
          9
          • J John Van

            For example, if I want to modify the text of the label in the background thread, I can use QTimer:: singlehot (0, label, [=] () {label ->setText ("abc");}) in program;

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

            @John-Van
            Although all the answers are excellent, especially @JKSH's explanation, I don't understand how your question and the code you show relate to each other. QTimer::singleShot() does not run in the background and does not involve another thread. Furthermore, and of particular note, are you aware that in Qt you must not access any UI element for either read or write in any other thread than the main UI one, so you cannot "modify the text of a label in a background/other thread" in any case? Unless you mean that it is your QTimer::singleshot() which itself is invoked from another thread while the label context is in the main thread, but I didn't get that from your phrasing.
            [UPDATE}
            And now @VRonin has expanded upon that by questioning how such a secondary thread would safely gain access to label anyway.

            J 1 Reply Last reply
            1
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #6

              To expand on JonB's post, I assume QTimer::singlehot(0, label, [=](){label->setText ("abc");}) is called from a secondary thread. That label pointer should never have made it to the secondary thread. It's a race condition unless it's atomic (e.g. QAtomicPointer).

              "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

              1 Reply Last reply
              2
              • E Offline
                E Offline
                ellen5898
                wrote on last edited by
                #7
                This post is deleted!
                1 Reply Last reply
                0
                • sierdzioS Offline
                  sierdzioS Offline
                  sierdzio
                  Moderators
                  wrote on last edited by
                  #8

                  Oh hello there, dear bot.

                  (Z(:^

                  1 Reply Last reply
                  3
                  • JonBJ JonB

                    @John-Van
                    Although all the answers are excellent, especially @JKSH's explanation, I don't understand how your question and the code you show relate to each other. QTimer::singleShot() does not run in the background and does not involve another thread. Furthermore, and of particular note, are you aware that in Qt you must not access any UI element for either read or write in any other thread than the main UI one, so you cannot "modify the text of a label in a background/other thread" in any case? Unless you mean that it is your QTimer::singleshot() which itself is invoked from another thread while the label context is in the main thread, but I didn't get that from your phrasing.
                    [UPDATE}
                    And now @VRonin has expanded upon that by questioning how such a secondary thread would safely gain access to label anyway.

                    J Offline
                    J Offline
                    John Van
                    wrote on last edited by
                    #9

                    @JonB
                    I use a demo to refine the details.

                    #include<Qtimer>
                    #include<QLabel>
                    #include<QThread>
                    #include<QApplication>
                    int main(int argc, char* argv[])
                    {
                        QApplication app(argc, argv);
                        auto lab = new QLabel("123");
                        lab->show();
                        //I ensure that the object to which the label pointer refers is not deleted after its creation, and the label pointer does not point to any other objects.
                        QThread::create([=]() {
                            //Assuming that the text of the label requires a lengthy calculation in the secondary thread, I simulate this by using sleep for one second in a simple thread
                            QThread::sleep(1);
                            //Then I want to directly set the value of the label in a non GUI thread
                            QTimer::singleShot(0, lab, [=]() { lab->setText("456"); });
                            })->start();
                        return app.exec();
                    }
                    

                    Is this an easier implementation than using Qt’s signals and slots?

                    jsulmJ 1 Reply Last reply
                    0
                    • J John Van

                      @JonB
                      I use a demo to refine the details.

                      #include<Qtimer>
                      #include<QLabel>
                      #include<QThread>
                      #include<QApplication>
                      int main(int argc, char* argv[])
                      {
                          QApplication app(argc, argv);
                          auto lab = new QLabel("123");
                          lab->show();
                          //I ensure that the object to which the label pointer refers is not deleted after its creation, and the label pointer does not point to any other objects.
                          QThread::create([=]() {
                              //Assuming that the text of the label requires a lengthy calculation in the secondary thread, I simulate this by using sleep for one second in a simple thread
                              QThread::sleep(1);
                              //Then I want to directly set the value of the label in a non GUI thread
                              QTimer::singleShot(0, lab, [=]() { lab->setText("456"); });
                              })->start();
                          return app.exec();
                      }
                      

                      Is this an easier implementation than using Qt’s signals and slots?

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

                      @John-Van You're updating the label in the second thread - this is not supported!
                      Use QMetaObject::invokeMethod() if you don't want to use signals/slots.

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

                      S 1 Reply Last reply
                      0
                      • jsulmJ jsulm

                        @John-Van You're updating the label in the second thread - this is not supported!
                        Use QMetaObject::invokeMethod() if you don't want to use signals/slots.

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

                        @jsulm said in Is using QTimer:: singlehot a good way to modify objects in other threads?:

                        You're updating the label in the second thread - this is not supported!

                        Actually, now he has a receiver object (lab) which I would expect to run the lambda in the correct thread.

                        Still, I agree that using QMetaObject::invokeMethod makes a lot more sense. Just for completeness' sake, here is how I use it:

                        QMetaObject::invokeMethod(qApp, [=]() { lab->setText("456"); });
                        

                        qApp works really well as a context object in this case. It is short to type and you don't have to figure out a good context object to place here. It is so common in our program (which is quite old, so I don't want to introduce signals everywhere), that I wrote a shorter function name guiThread(...) which just takes the lambda. You can get it from https://github.com/SimonSchroeder/QtThreadHelper. It also makes the intent much clearer that you are trying to run code inside the GUI thread.

                        1 Reply Last reply
                        3

                        • Login

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