Relevance of invokeMethod() in multithreaded programs
-
@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.@SimonSchroeder
Thanks. I think I understand this. I had been about to post to ask what you had meant byYes, 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-nameSLOT()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 signalconnect()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?
-
@SimonSchroeder
Thanks. I think I understand this. I had been about to post to ask what you had meant byYes, 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-nameSLOT()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 signalconnect()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?
@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... } -
@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... }@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 oldSIGNAL()/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 overconnect()s. And why it is regarded as especially useful when multithreaded. -
-
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
invokeMethodoverloads (with aconst chat *membersecond 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?
invokeMethodsaves 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); }); -
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. -
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()? -
@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 oldSIGNAL()/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 overconnect()s. And why it is regarded as especially useful when multithreaded.@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
myListisn't even held by a QObject at all? -
-
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 functionguiThreadMaybe()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.
-
J JonB has marked this topic as solved