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. [solved] Slot invoked in context of wrong thread !?
Forum Updated to NodeBB v4.3 + New Features

[solved] Slot invoked in context of wrong thread !?

Scheduled Pinned Locked Moved General and Desktop
10 Posts 3 Posters 3.4k 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.
  • M Offline
    M Offline
    MuldeR
    wrote on last edited by
    #1

    Hi.

    I have the following situation: I have a GUI application that creates a "background" thread. The thread class is derived from QThread. Inside this "background" thread, a large number of sub-tasks need to be executed. These tasks, derived from QRunable, are created and added to a QThreadPool. This all happens inside the "background" thread, the Main/GUI thread is not involved at all here.

    Now, I also need the "background" thread to get a Signal when one of the tasks has finished (in which case it will either start the next tasks or exit). So the thread class has a Slot "taskDone", which will be connected, via a queued connection, to each task object before the task is started. And the task object will emit the Signal once it is done. The "background" thread also runs an event loop, i.e. it calls exec() after the first few tasks have been created/started. All seems straight forward.

    Now, I have noticed that the "taskDone" slot is actually invoked in the context of the Main/GUI thread, rather than the "background" thread! So can somebody explain why that is? To my understand, the purpose of a "queued" connection is that the slot will be invoked in the context of the thread to which the receiving object belongs - which clearly would be the "background" thread in this case...

    [quote]Qt::QueuedConnection

    The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.[/quote]

    Thanks!

    My OpenSource software at: http://muldersoft.com/

    Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

    Go visit the coop: http://youtu.be/Jay...

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by
      #2

      An object derived from QThread does not live in the thread it manages. It's just its run method is executed in separate thread when you call start. The object itself still lives in the thread it was created in, which is the main thread in your case.

      That is why there's moveToThread() and why deriving from QThread is not the recommended way of doing multithreading.

      1 Reply Last reply
      0
      • M Offline
        M Offline
        MuldeR
        wrote on last edited by
        #3

        [quote author="Chris Kawa" date="1406990551"]An object derived from QThread does not live in the thread it manages. [...] The object itself still lives in the thread it was created in, which is the main thread in your case.[/quote]

        I see. That makes sense. Especially when considering that, at the time when the QThread object is created, the thread it manages doesn't even exist yet.

        And moveToThread() fixed my problem, indeed.

        Thanks!

        My OpenSource software at: http://muldersoft.com/

        Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

        Go visit the coop: http://youtu.be/Jay...

        1 Reply Last reply
        0
        • Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Great.
          I just hope you didn't do moveToThread(this) ;)

          1 Reply Last reply
          0
          • M Offline
            M Offline
            MuldeR
            wrote on last edited by
            #5

            That's exactly what was needed.

            My OpenSource software at: http://muldersoft.com/

            Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

            Go visit the coop: http://youtu.be/Jay...

            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              "You're doing it wrong":http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/

              1 Reply Last reply
              0
              • JKSHJ Offline
                JKSHJ Offline
                JKSH
                Moderators
                wrote on last edited by
                #7

                Hi MuldeR, here's what the "official documentation":http://qt-project.org/doc/qt-5/qthread.html says (emphasis added):

                [quote]It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.[/quote]

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

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  MuldeR
                  wrote on last edited by
                  #8

                  bq. My #1 biggest gripe with this code is moveToThread(this); I see so many people using this without understanding what it does. What does it do, you ask? The moveToThread() function tells Qt to ensure that event handlers, and by extension signals and slots, are called from the specified thread context.

                  Since I do understand what it does and since that's exactly what I want/need here, I'm not doing it wrong ;-)

                  I understand that I could create a separate worker object. But I don't see how having to maintain a separate worker object benefits my project. The argument for this approach seem to be that inheriting from QThread is evil, because "it’s confusing" and "not how QThread was designed to be used". The former is quite subjective and, personally, I can't agree. The latter is a bit unspecific. So what exactly would be the real drawback for my project?

                  My OpenSource software at: http://muldersoft.com/

                  Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

                  Go visit the coop: http://youtu.be/Jay...

                  1 Reply Last reply
                  0
                  • JKSHJ Offline
                    JKSHJ Offline
                    JKSH
                    Moderators
                    wrote on last edited by
                    #9

                    [quote author="MuldeR" date="1407079364"]Since I do understand what it does and since that's exactly what I want/need here, I'm not doing it wrong ;-)

                    I understand that I could create a separate worker object. But I don't see how having to maintain a separate worker object benefits my project. The argument for this approach seem to be that inheriting from QThread is evil, because "it’s confusing" and "not how QThread was designed to be used". The former is quite subjective and, personally, I can't agree. The latter is a bit unspecific. So what exactly would be the real drawback for my project?[/quote]I suppose there's a subtle difference between "wrong" and "anti-pattern".

                    If you understand the mechanisms, then feel free to deviate from established patterns where you find appropriate. After all, you are the designer for your project. There is no drawback to your project.

                    However, do take time to understand why the (anti-)pattern exists in the first first place. In this case, it was very common for users to shoot themselves in the foot when adding slots to QThread subclasses. That's why it's considered an anti-pattern.

                    The Qt documentation is now very clear: If you want slots to be invoked in the context of a new thread, use a worker object. If you want to run code in another thread without don't need an event loop, subclass QThread.

                    Anyway, how much difference is there between maintaining a worker object vs. maintaining your custom QThread?

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

                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      MuldeR
                      wrote on last edited by
                      #10

                      [quote author="JKSH" date="1408365353"]However, do take time to understand why the (anti-)pattern exists in the first first place. In this case, it was very common for users to shoot themselves in the foot when adding slots to QThread subclasses. That's why it's considered an anti-pattern.[/quote]

                      I only find it "natural" that if a QThread creates internal objects inside it's run() method and connects to these objects (with queued connection), then the corresponding slots will be invoked in the context of the thread that is controlled by the QThread object and that is executing the run() method - rather than in the context of the "main" thread, which may be in whatever state that we don't know and don't want to care about at this point...

                      [quote author="JKSH" date="1408365353"]Anyway, how much difference is there between maintaining a worker object vs. maintaining your custom QThread?[/quote]

                      Well, it means that I will now have to maintain two separate objects, the QThread and the Worker object - for something that logically, i.e. from the caller's perspective, should be a single "background task" object. Of course we don't want to the caller having to create two separate objects and having to connect them in a certain way in order to get everything working as expected. Actually, we don't want the caller having to worry about such "details" at all. So, in the end, I would probably end up wrapping the QThread object and its Worker object into yet another "high level" class that provides a clean interface to the caller and hides the implementation details. That's all very doable! But still adds a significant amount of extra complexity - which I don't want to add unless it gives a real benefit (or avoids a real problem)...

                      My OpenSource software at: http://muldersoft.com/

                      Qt v4.8.6 MSVC 2013, static/shared: http://goo.gl/BXqhrS

                      Go visit the coop: http://youtu.be/Jay...

                      1 Reply Last reply
                      0

                      • Login

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