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. Relevance of invokeMethod() in multithreaded programs
Qt 6.11 is out! See what's new in the release blog

Relevance of invokeMethod() in multithreaded programs

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 5 Posters 774 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic was forked from Show a QMessage box from the context of a function defined outside mainwindow.cpp JKSH
This topic has been deleted. Only users with topic management privileges can see it.
  • S SimonSchroeder

    @JonB said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

    Never used invokeMethod(). Is it synchronous or asynchronous?

    invokeMethod() basically lets you post calls to slots in the event queue. That's at least how I am using it. I makes it easier to not have a bunch of signals just so you connect them and call them once.

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote last edited by
    #1

    @SimonSchroeder
    Thanks. I think I understand this. I had been about to post to ask what you had meant by

    Yes, invokeMethod() is also my general solution if I'm multithreaded.

    I didn't see why there is a particular mention here of separate threads. Still not sure why there is? Is there anything in what you have written which makes this especially apposite to cross-thread rather than single-thread? Your point about avoiding many signals/slots, but why is the multithread relevant?

    It sounds to me as though invokeMethod() is just sort of the heart of the older call-slot-by-name SLOT() code approach?

    Having heard of but never used it, I had thought it did some kind of "invoke method on object from thread in which object lives", context switching for you if not current thread. So you didn't have to worry about threads being different. Ah, I guess it does if you pass it Qt::AutoConnection, just like signal connect()s. But it doesn't do it there and then, it uses the usual Qt delayed queuing if across threads. I had thought it was doing something more immediate.

    OK, so since it looks like it's a quick fire-slot-as-though-connected, why do you find it particularly suitable in multithreaded?

    JKSHJ 1 Reply Last reply
    0
    • JonBJ JonB

      @SimonSchroeder
      Thanks. I think I understand this. I had been about to post to ask what you had meant by

      Yes, invokeMethod() is also my general solution if I'm multithreaded.

      I didn't see why there is a particular mention here of separate threads. Still not sure why there is? Is there anything in what you have written which makes this especially apposite to cross-thread rather than single-thread? Your point about avoiding many signals/slots, but why is the multithread relevant?

      It sounds to me as though invokeMethod() is just sort of the heart of the older call-slot-by-name SLOT() code approach?

      Having heard of but never used it, I had thought it did some kind of "invoke method on object from thread in which object lives", context switching for you if not current thread. So you didn't have to worry about threads being different. Ah, I guess it does if you pass it Qt::AutoConnection, just like signal connect()s. But it doesn't do it there and then, it uses the usual Qt delayed queuing if across threads. I had thought it was doing something more immediate.

      OK, so since it looks like it's a quick fire-slot-as-though-connected, why do you find it particularly suitable in multithreaded?

      JKSHJ Offline
      JKSHJ Offline
      JKSH
      Moderators
      wrote last edited by JKSH
      #2

      @JonB said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

      why do you find it particularly suitable in multithreaded?

      You can run ANY function in any thread of your choice that has an active event loop:

      auto o1 = new QObject;
      o1->moveToThread(thread1);
      
      auto o2 = new QObject;
      o2->moveToThread(thread2);
      
      ...
      
      foo(); // Run foo() in the current thread
      
      QMetaObject::invokeMethod(o1, []{
          foo(); // Run foo() in thread1
      });
      QMetaObject::invokeMethod(o2, []{
          foo(); // Run foo() in thread2
      });
      QMetaObject::invokeMethod(qApp, []{
          foo(); // Run foo() in the GUI thread
      });
      

      Lambdas + invokeMethod() also provides another easy way to pass data between threads:

      bool stopProcessing = false;
      
      QMetaObject::invokeMethod(qApp, [&stopProcessing]{
          // Show message box in the GUI thread
          auto btn = QMessageBox::question(nullptr, "Uh-oh", "Houston, we have a problem. Permission to abort mission?");
      
          // Return data to the secondary thread
          stopProcessing = (btn == QMessageBox::Yes);
      
      }, Qt::BlockingQueuedConnection); // Block the secondary thread until the lambda returns
      
      // Read and use the data in secondary thread
      if (stopProcessing) {
          // I'm free!
      } else {
          // Save me...
      }
      

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

      JonBJ 1 Reply Last reply
      2
      • JKSHJ JKSH

        @JonB said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

        why do you find it particularly suitable in multithreaded?

        You can run ANY function in any thread of your choice that has an active event loop:

        auto o1 = new QObject;
        o1->moveToThread(thread1);
        
        auto o2 = new QObject;
        o2->moveToThread(thread2);
        
        ...
        
        foo(); // Run foo() in the current thread
        
        QMetaObject::invokeMethod(o1, []{
            foo(); // Run foo() in thread1
        });
        QMetaObject::invokeMethod(o2, []{
            foo(); // Run foo() in thread2
        });
        QMetaObject::invokeMethod(qApp, []{
            foo(); // Run foo() in the GUI thread
        });
        

        Lambdas + invokeMethod() also provides another easy way to pass data between threads:

        bool stopProcessing = false;
        
        QMetaObject::invokeMethod(qApp, [&stopProcessing]{
            // Show message box in the GUI thread
            auto btn = QMessageBox::question(nullptr, "Uh-oh", "Houston, we have a problem. Permission to abort mission?");
        
            // Return data to the secondary thread
            stopProcessing = (btn == QMessageBox::Yes);
        
        }, Qt::BlockingQueuedConnection); // Block the secondary thread until the lambda returns
        
        // Read and use the data in secondary thread
        if (stopProcessing) {
            // I'm free!
        } else {
            // Save me...
        }
        
        JonBJ Offline
        JonBJ Offline
        JonB
        wrote last edited by
        #3

        @JKSH said in Relevance of invokeMethod() in multithreaded programs:

        You can run ANY function in any thread of your choice that has an active event loop:

        • The docs state "Invokes the member (a signal or a slot name) on the object obj.". That implies to me you need to have marked the desired member method as a slot. Maybe it does not matter with slots...?

        • The docs state "With asynchronous method invocations, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes. ". So just like signals/slots you need support for each data type?

        • You are using a runtime lookup of member function name and parameter numbers and types. So you lose the compile-time checking of parameters/signatures in modern connect(). It's even slightly worse than the old SIGNAL()/SLOT() mechanism, didn't that check signatures of each for compatibility?

        • It just seems to do the same as if you had set up a connect(), but saves you having to do that, not really anything else?

        Particularly from the last point, I then wonder why Simon says this is especially useful in a multithreaded context? Thinking aloud, perhaps when you want to call a function within same thread you can often just call it directly without any kind of signal/slot/connect()/invokeMethod() but that is not so easy if the function is in another thread so invokeMethod() is a convenient way if you have not gone signal/slot/connect() approach?

        I am not trying to be difficult. I am just trying to understand invokeMethod() and why/when you would use it over connect()s. And why it is regarded as especially useful when multithreaded.

        JKSHJ 1 Reply Last reply
        0
        • GrecKoG Offline
          GrecKoG Offline
          GrecKo
          Qt Champions 2018
          wrote last edited by GrecKo
          #4

          The docs state "Invokes the member (a signal or a slot name) on the object obj.". That implies to me you need to have marked the desired member method as a slot. Maybe it does not matter with slots...?

          The doc states that for a subset of the invokeMethod overloads (with a const chat *member second argument). Other states "Invokes the function [...] in the event loop of context. function can be a functor or a pointer to a member function."

          Those don't need to be marked as slot.

          The docs state "With asynchronous method invocations, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes. ". So just like signals/slots you need support for each data type?

          Yes but nowadays the meta-object system is mostly automatic and you don't need explicit registration.

          3rd point is moot given the overloads taking a functor or member-function pointer.

          It just seems to do the same as if you had set up a connect(), but saves you having to do that, not really anything else?

          invokeMethod saves you the unnecessary plumbing and leaking (eh) your internal implementation when there is already an existing coupling between the caller and the callee.
          When I want to call a known function in another thread, that's what I use. Signals are for notifying unknown (to the caller) external objects of an event they may be interested in.

          One of my common usage is modifying GUI stuff in the GUI thread from a background thread. For example I have a background thread compiling a list of data to be presented in a view via a model:

          // populate myList
          QMetaObject::invokeMethod(m_model, [=] { m_model->setNewMyList(myList); });
          
          1 Reply Last reply
          1
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote last edited by
            #5

            Hi,

            To add to my fellows answers, in the case of a callback, it allows to call into Qt's meta object without requiring complex plumbing.
            If memory serves well, I used to do that with some camera SDK's that provided callback running in different threads to update the GUI in a straightforward fashion.

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • JonBJ Offline
              JonBJ Offline
              JonB
              wrote last edited by
              #6

              Hmm. As I say, I have never used it, though seen others doing so. My usage of Qt may be different from you all. I did understand @GrecKo's post. But the example of

              // populate myList
              QMetaObject::invokeMethod(m_model, [=] { m_model->setNewMyList(myList); });
              

              just looks to me like I natural example of emitting a signal for "here is some new data for the model", so I don't really see why it's important to have that using invokeMethod()?

              1 Reply Last reply
              0
              • JonBJ JonB

                @JKSH said in Relevance of invokeMethod() in multithreaded programs:

                You can run ANY function in any thread of your choice that has an active event loop:

                • The docs state "Invokes the member (a signal or a slot name) on the object obj.". That implies to me you need to have marked the desired member method as a slot. Maybe it does not matter with slots...?

                • The docs state "With asynchronous method invocations, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes. ". So just like signals/slots you need support for each data type?

                • You are using a runtime lookup of member function name and parameter numbers and types. So you lose the compile-time checking of parameters/signatures in modern connect(). It's even slightly worse than the old SIGNAL()/SLOT() mechanism, didn't that check signatures of each for compatibility?

                • It just seems to do the same as if you had set up a connect(), but saves you having to do that, not really anything else?

                Particularly from the last point, I then wonder why Simon says this is especially useful in a multithreaded context? Thinking aloud, perhaps when you want to call a function within same thread you can often just call it directly without any kind of signal/slot/connect()/invokeMethod() but that is not so easy if the function is in another thread so invokeMethod() is a convenient way if you have not gone signal/slot/connect() approach?

                I am not trying to be difficult. I am just trying to understand invokeMethod() and why/when you would use it over connect()s. And why it is regarded as especially useful when multithreaded.

                JKSHJ Offline
                JKSHJ Offline
                JKSH
                Moderators
                wrote last edited by JKSH
                #7

                @JonB said in Relevance of invokeMethod() in multithreaded programs:

                • It just seems to do the same as if you had set up a connect(), but saves you having to do that, not really anything else?

                Particularly from the last point, I then wonder why Simon says this is especially useful in a multithreaded context?

                Have you had a closer look at my threaded QMessageBox example? (Note: I don't generally encourage blocking connections, but there are niche use-cases for it; it's a demonstration of what's possible)

                @JonB said in Relevance of invokeMethod() in multithreaded programs:

                the example of

                // populate myList
                QMetaObject::invokeMethod(m_model, [=] { m_model->setNewMyList(myList); });
                

                just looks to me like I natural example of emitting a signal for "here is some new data for the model", so I don't really see why it's important to have that using invokeMethod()?

                What if you DON'T have a signal? What if myList isn't even held by a QObject at all?

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

                1 Reply Last reply
                1
                • S Offline
                  S Offline
                  SimonSchroeder
                  wrote last edited by
                  #8

                  Basically, the other answers already contain all of my thoughts. But, since I've been mentioned I'll still chime in.

                  In a single-threaded context I can just call functions and that's fine. In a multi-threaded context when I want to call functions of an object that lives in a different thread (especially if you want to call GUI functions in Qt) invokeMethod() is the only easy way I know of. Sure, you can properly set up a signal. I personally don't see the point in having a signal (which I then need to connect) if it is called from just a single place in the code. First, I have to come up with an appropriate name for the signal, and second, I'll have a long list of signals in the class declaration that are of no interest to any outsider.

                  The use case of of using this to call functions belonging to a GUI thread is so pervasive that I have a header-only library that (among other things) has a function guiThread(...) (https://github.com/SimonSchroeder/QtThreadHelper) to easily place calls into the GUI thread from other threads. From the recent discussion in this forum I have also learned that invokeMethod() takes a connection type as argument. I guess, then my function guiThreadMaybe() is not necessary, as the default is the AutoConnection which will do already a direct call if it is from the same thread (the 'maybe' part explicitly checks for that).

                  Outside of multi-threading I only see a single use case for invokeMethod(): If I don't want to immediately execute that function, but put it in the event queue to be executed at a later point. I guess this is a valid use case, but not one I encounter often. In many cases, the suggested solution is a single shot timer with a timeout of 0ms. In addition to putting this call into the event loop, it will also only execute once the event loop is otherwise idle.


                  @JonB said in Relevance of invokeMethod() in multithreaded programs:

                  I didn't see why there is a particular mention here of separate threads.

                  It wasn't mentioned in the original post, but later:
                  @Christian-Ehrlicher said in Show a QMessage box from the context of a function defined outside mainwindow.cpp:

                  One problem with a simple callback will arise when you run the solver in a different thread.

                  "invokeMethod() is also my general solution if I'm multithreaded" needs to be read in the context of the original discussion: It was specifically about calling GUI functions. If we combine that with multithreading, invokeMethod() is the (hard-to-find) obvious solution.

                  1 Reply Last reply
                  2
                  • JonBJ JonB has marked this topic as solved

                  • Login

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