Unsolved Thread safety of QMetaObject::invokeMethod e.g. slot invoking from random threads
-
It seems to me QMetaObject::invokeMethod with Qt::QueuedConnectionis a common seen pattern to invoke slots from non qt managed, especially non main threads. However QMetaObject::invokeMethod is not documented as thread safe, as far as I can tell, but it's behaviour suggests it.
Is it thread safe or not?
If not what would be a good alternative to invoke slots on QMetaObjects from non qt managed threads? Background ( https://stackoverflow.com/q/53803018/3537677 ) -
It's not documented as thread-safe because it can't be guaranteed. e.g. when the receiver is deleted during the invokeMethod() call you'll get in trouble. When you don't modify the receiver (which is likely the case in your usecase) it's thread-safe afaics.
-
@Christian-Ehrlicher said in Thread safety of QMetaObject::invokeMethod e.g. slot invoking from random threads:
when the receiver is deleted
I would not define this as thread-safe, it would be thread safe, if the internals of QMetaObject::invokeMethod is reentrant, and given the caller makes sure about the life times, i.e. documented constraint on it's parameters. First statement includes the thread safe handling of Qt globals.
it's thread-safe afaics
Exactly that "AFAIK" is what my question here is about. Because either it's true, then it should be documented, or not, which would mean many solutions are wrong, and the questions remains, what could be used.
-
Since I don't know the exact internals the only way I see is to create a bug report report and ask directly.
-
@Christian-Ehrlicher said in Thread safety of QMetaObject::invokeMethod e.g. slot invoking from random threads:
Since I don't know the exact internals the only way I see is to create a bug report report and ask directly.
Just opened
https://bugreports.qt.io/browse/QTBUG-72599 -
I don't think this will be thread safe. This will get instance of metaobject and is single instance for all the subclasses of qobject. QObject itself is not thread safe. Invoke method access many internal pointers which are not protected. It also accesses qobject pointer
-
The specific problem was about a queued connection which is more or less a QCoreApplication::postEvent() which is thread safe ...
-
invokeMethod
is thread-safe with theQt::QueuedConnection
argument in the sense that it's going to do what you expect it to - i.e. put a message in the receiving thread's event loop for a meta-call. It is most certainly not thread-safe when used withQt::AutoConnection
.I would not define this as thread-safe, it would be thread safe, if the internals of QMetaObject::invokeMethod is reentrant
Thread-safety and reentrancy are orthogonal to each other. A function can be thread-safe and non-reentrant (which
invokeMethod
actually is with theQt::QueuedConnection
, as it operates on the threading globals) or vice versa ... or any combination thereof. -
If it is queues connection as @kshegunov said it will just place in destination thread and move on. If multiple threads call same method with queued connection I don't see issue. If it mixes connection type then it shud create issue.
-
@kshegunov said in Thread safety of QMetaObject::invokeMethod e.g. slot invoking from random threads:
Thread-safety and reentrancy are orthogonal to each other.
I know, however since we don't have to deal with Interrupts here, in practice reentrancy usually is a precondition for thread safety, because, when a function can not be called in thread A, while it has been execute to some in between state in Thread B, what is thread safety then.But anyway, that constraints, like "QMetaObject::invokeMethod is thread safe when called with Qt::QueuedConnection and with recipient and parameters living at least until slot completion or something" should be documented, so one can be sure, that it really is. (However for the parameters should be fine with Q_ARGS, call by value AFAIK)
-
I think you misunderstand.
QMetaObject::invokeMethod
does not execute the method when it's called withQt::QueuedConnection
, which is the whole point of it. Instead it creates a QEvent::MetaCall event and puts it into the receiving object's thread's event queue. This all means that the event is processed (as all posted events) synchronously from the receiving thread's event loop. So you kind of lose the idea of "thread-safe" as you're not really calling the method itself. The receiving thread will call it when it gets to it. Unless if you mean if the actual event posting is thread-safe, then the answer is "yes, most certainly". -
@kshegunov said in Thread safety of QMetaObject::invokeMethod e.g. slot invoking from random threads:
Unless if you mean if the actual event posting is thread-safe, then the answer is "yes, most certainly".
Exactly that is what I meant! Thats the reason why I tried to use QCoreApplication::postEvent first, since it seemed to me as the only thread safe way, to post an event to the global qt event queue.
-
Thats the reason why I tried to use QCoreApplication::postEvent first
It is one way. You can't create
QEvent::MetaCall
events for it, however, this is whereQMetaObject::invokeMethod
comes into play.to post an event to the global qt event queue.
There's no global event queue, there's an event queue for each thread that starts one with
QEventLoop::exec
(which the main thread does throughQCoreApplication::exec
). -
@kshegunov said in Thread safety of QMetaObject::invokeMethod e.g. slot invoking from random threads:
There's no global event queue, there's an event queue for each thread that starts one with
QEventLoop::exec
(which the main thread does throughQCoreApplication::exec
).Yeah sorry, I often forget that you can also create extra QThreads/Widgets with own event loops. With global I meant of course the stuff you get by QCoreApplication::instance, like you said, (which AFAIK is special as it needs to be pumped in order to Qt in general to work), but thanks for clarifying.
However I just posted my "solution" aka version of the common pattern: https://stackoverflow.com/a/53806409/3537677 with also some assumptions by me, which of course you are invited to review!
-
@Superlokkus said in Thread safety of QMetaObject::invokeMethod e.g. slot invoking from random threads:
which AFAIK is special as it needs to be pumped in order to Qt in general to work
No not really.
QCoreApplication::exec
just doesQEventLoop::exec
... :)PS:
Ah, I see Giuseppe already answered you. One note on your call, if you're using Qt 5.10+ you can useQMetaObject::invokeMethod
with functors (i.e. lambdas or pointers to methods), which is often more convenient and less error prone than resolving the method address through its name.