Invoking a slot from a non-Qt thread
-
I correct to think that there's only two ways to invoke a slot from a non-QObject based thread?
-
Use QMetaObject::invokeMethod(), or
-
emit a signal (can I do that on a non Qt thread?)
Thanks
Davidwrote 29 days ago last edited by@Perdrix
@Christian-Ehrlicher will correct me if I am wrong. Yes, you can emit a signal from a non-QObject based thread. But you still need a "context object" to emit the signal and pass to theconnect()
. And that needs to be aQObject
. And you will use a queued connection. I guessQMetaObject::invokeMethod()
will skip the need to have an emittingQObject
.You will also a need a receiving
QObject
, for both cases. The Qt event loop needs to be running in the receiver thread to dispatch the slots.Am I right, Christian?
References:
https://stackoverflow.com/questions/41044526/qt-5-emit-signal-from-non-qt-thread
https://stackoverflow.com/questions/24982324/qt-emit-a-signal-from-a-c-thread
https://www.qtcentre.org/threads/65029-Emitting-signal-from-a-non-Qt-Thread -
-
@Perdrix
@Christian-Ehrlicher will correct me if I am wrong. Yes, you can emit a signal from a non-QObject based thread. But you still need a "context object" to emit the signal and pass to theconnect()
. And that needs to be aQObject
. And you will use a queued connection. I guessQMetaObject::invokeMethod()
will skip the need to have an emittingQObject
.You will also a need a receiving
QObject
, for both cases. The Qt event loop needs to be running in the receiver thread to dispatch the slots.Am I right, Christian?
References:
https://stackoverflow.com/questions/41044526/qt-5-emit-signal-from-non-qt-thread
https://stackoverflow.com/questions/24982324/qt-emit-a-signal-from-a-c-thread
https://www.qtcentre.org/threads/65029-Emitting-signal-from-a-non-Qt-Thread@JonB said in Invoking a slot from a non-Qt thread:
Am I right, Christian?
Yes, but the question was if it can be invoked from a std::thread (or other non QThread based one). Nothing about what object it is 🙂
-
@JonB said in Invoking a slot from a non-Qt thread:
Am I right, Christian?
Yes, but the question was if it can be invoked from a std::thread (or other non QThread based one). Nothing about what object it is 🙂
wrote 29 days ago last edited by JonB 5 Mar 2025, 12:04@Christian-Ehrlicher said in Invoking a slot from a non-Qt thread:
Yes, but the question was if it can be invoked from a std::thread (or other non QThread based one). Nothing about what object it is 🙂
Oh indeed! And the reference links are about that, e.g. the second one is about
I want to emit a signal from a C++ thread (std::thread) in Qt.
I just meant that OP is going to need to Qt objects around from somewhere in the thread. I agree with you that
emit
signal is the obvious route. But, just for the record, a non-Qt thread can useQMetaObject::invokeMethod()
to call a slot if it has access to a receiving object but not a sending one to do aconnect()
. Right? -
@Christian-Ehrlicher said in Invoking a slot from a non-Qt thread:
Yes, but the question was if it can be invoked from a std::thread (or other non QThread based one). Nothing about what object it is 🙂
Oh indeed! And the reference links are about that, e.g. the second one is about
I want to emit a signal from a C++ thread (std::thread) in Qt.
I just meant that OP is going to need to Qt objects around from somewhere in the thread. I agree with you that
emit
signal is the obvious route. But, just for the record, a non-Qt thread can useQMetaObject::invokeMethod()
to call a slot if it has access to a receiving object but not a sending one to do aconnect()
. Right?@JonB said in Invoking a slot from a non-Qt thread:
a non-Qt thread can use QMetaObject::invokeMethod() to call a slot if it has access to a receiving object but not a sending one to do a connect(). Right?
Yes. But imo it's better to define a signal in the receiver which then does the thread context switch.
-
In order to emit a signal or use
QMetaObject::invokeMethod()
from another thread, it doesn't technically have to be aQThread
. What's required is an event loop and the emitter / invoker to inherit fromQObject
. But if you develop an application with Qt, why not useQThread
anyway?We've seen an implementation in this topic, that circumvents missing
QObject
inheritance / event loop. It implements methods in aQObject
wrapping aQMetaObject::invokeMethod()
call on itself. The caller just calls the wrapper from another thread. While it might technically work, I would clearly not recommend it. Instead, make the caller inherit fromQObject
and let it live in anotherQThread
. All problems solved cleanly. -
In order to emit a signal or use
QMetaObject::invokeMethod()
from another thread, it doesn't technically have to be aQThread
. What's required is an event loop and the emitter / invoker to inherit fromQObject
. But if you develop an application with Qt, why not useQThread
anyway?We've seen an implementation in this topic, that circumvents missing
QObject
inheritance / event loop. It implements methods in aQObject
wrapping aQMetaObject::invokeMethod()
call on itself. The caller just calls the wrapper from another thread. While it might technically work, I would clearly not recommend it. Instead, make the caller inherit fromQObject
and let it live in anotherQThread
. All problems solved cleanly.wrote 29 days ago last edited by@Axel-Spoerl said in Invoking a slot from a non-Qt thread:
But if you develop an application with Qt, why not use QThread anyway?
I agree. But don't you think Mr @Perdrix is going to say "because it's already in someone else's code which I don't want to change but instead work with"? :)
-
wrote 29 days ago last edited by
The application was not developed using Qt it was developed using MFC. We have converted it to Qt over the last two to three years (it was a pretty large job). Where it was helpful and expedient we did use QThreads, but there are other bits of threading that we've not (yet) got round to...
-
Sounds like squeezing toothpaste back into the tube.
I'd probably go for an interface class, living inside the std::thread, inheriting fromQObject
and running its ownQEventLoop
.
That class can provide wrappers to either invoke methods in other threads, or emit signals.
In the moment you could replace the whatever thread with aQThread
, you can untangle the interface class and do the calls directly. -
I haven't tried anything, but can't you simply pass a qt signal als callback function? Any connects won't auto default to QtQueuedConnection as there's no thread info due to no QThread but you can manage that manually
-
Sounds like squeezing toothpaste back into the tube.
I'd probably go for an interface class, living inside the std::thread, inheriting fromQObject
and running its ownQEventLoop
.
That class can provide wrappers to either invoke methods in other threads, or emit signals.
In the moment you could replace the whatever thread with aQThread
, you can untangle the interface class and do the calls directly.wrote 27 days ago last edited by@Axel-Spoerl said in Invoking a slot from a non-Qt thread:
I'd probably go for an interface class, living inside the std::thread, inheriting from QObject and running its own QEventLoop.
From what I understand only the calling thread does not have anything Qt-based. In order to emit a signals there is no need to start an event loop inside that non-Qt thread. Only a receiving slot would require an event loop. Or am I wrong about this?
The quickest way would certainly be using invokeMethod. However, if you can (and are willing to) using signals is always better. If you don't want to introduce any Qt into that thread (yet) you can have a regular C++ function inside some existing Qt code and call that. This function can either use invokeMethod or even emit a signal for your.
If it is inevitable to keep Qt out of your thread (in the long run) it makes sense to create something derived from QObject to be used inside your non-Qt thread. Then you can emit a signal using this object. I don't think you need anything special in the calling thread.
emit
is just a Qt keyword that gets removed by the preprocessor. From the compiler's point of view emitting a signal is just calling a regular member function. (The member function for the signal is generated bymoc
.) You need to be careful about object lifetimes. The calling object needs to live long enough for the slot to be executed. If the calling or receiving object in aconnect
statement is deleted, all queued slot invocations are also removed. Also, as your non-Qt thread does not have an event loop you cannot usedeleteLater()
to delete the object. If you cannot guarantee that your non-Qt thread runs long enough for the slot to be executed (or rather at least started) inside the Qt thread (and thus cannot guarantee a long lifetime for the QObject-derived object) usinginvokeMethod
is the safest way. Maybe it even makes the most sense to useinvokeMethod
if you don't rely on member variables of the calling object, but instead hand over all data necessary for the slot as function arguments. It certainly avoid thinking about object lifetimes (and thread lifetimes).
12/12