Unsolved QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever
-
@sykac
Hi there, i am not expert with QThread but have you tried to use a request and response signals to invoke and receive the data from your worker thread to main thread ?Obs: I don't know if this is the best way to request data from thread.
-
@sykac said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
Then the worker starts the infinite loop, yes.
What infinite loop, can you show us?
If you block the event loop then that means you can't process queued events, thus your call withBlockingQueuedConnection
will just hang there until the actual event posted in the event queue is processed.@KillerSmath said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
Obs: I don't know if this is the best way to request data from thread.
It is, indeed.
-
@kshegunov
Okay, i told it because i readed some topics about send data using signals and noticed that it's not recommended to send data in signals because they makes a copy of data to send as parameter and another copy is made at slot, and make copy can takes time depending of data size. -
That's why Qt leverages implicit sharing to begin with. When you have the case that the signal/slot parameter(s) have to copy big-ish data chunks, then it's time to use
QSharedData
andQSharedDataPointer
. This way you get the shallowest copies possible - i.e. a pointer being copied, and whenever you have a write operation the data would detach if it's shared. -
@KillerSmath said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
use a request and response signals to invoke and receive the data from your worker thread to main thread ?
Even this solution requires a non-blocked event loop running on the worker-thread side
@kshegunov said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
whenever you have a write operation the data would detach if it's shared.
Worth mentioning in this context that it is thread safe as long as const means thread safe or you use
QExplicitlySharedDataPointer
to make thread safe.I'm not that knowledgeable of Qt internals to assure you but I'd guess most if not all the Qt classes are usable without thinking about copying
-
@VRonin said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
Worth mentioning in this context that it is thread safe as long as const means thread safe or you use QExplicitlySharedDataPointer to make thread safe.
Eh, what? I did not at all mention thread safety. But in any case so we clear the issue here - no, the data is not thread-safe. The only thing that is thread-safe (sort of) in the whole scheme is the data copying, which happens behind the scenes. And this is just so you can delay the actual copy as long as possible, and to ensure that your objects behave correctly when it comes to reentrancy (if you have statics the object will still not be reentrant). This in no way guards the actual data from concurrent access! (bold!)
-
Thanks for suggestions guys.
@kshegunov My infinite loop is
while(flag) doStuff();
, so it's definitely because of it. So ifdoStuff()
was connected to a timer and wasn't in the while loop, it would work?But I'll probably stick with the object in the main thread simply calling the method of the worker which will be executed in the main thread. And as you're mentioning thread safety and data manipulation - is this safe?
-
@kshegunov said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
I did not at all mention thread safety.
I know, I just brought it up as this thread was about multithreading
@kshegunov said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
This in no way guards the actual data from concurrent access!
What I meant is that if type
T
is reentrant, usingQSharedData
does not break reentrancy as both the reference counter anddetach()
are thread safe.
If you haveconst
methods that actually change the internal state then you still have a race condition (as in this caseconst
!= thread safe) -
Remember, it is not a good practice to use an infinite loop in a thread, but you can solve your problem using
processEvents
inside your loop to force your worker to process the events.Below is an example of how you can implement:
worker.h
#ifndef WORKER_H #define WORKER_H #include <QObject> #include <QMutex> class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = nullptr); ~Worker(); signals: // get data using signals void requestData(); void responseData(const int number); void finished(); public slots: void process(); void stop(); int getData(); private: QMutex m_mutex; bool m_stop; int m_data; void doStuff(); }; #endif // WORKER_H
worker.cpp
#include "worker.h" #include <QCoreApplication> //#include <QMutexLocker> Worker::Worker(QObject *parent) : QObject(parent) { m_data = 0; m_stop = false; connect(this, &Worker::requestData, this, [this](){ // if prefer to use signals to return data // checksum or processing the data // ... // ... // done checksum or processing emit responseData(m_data); }); } Worker::~Worker(){ // m_mutex.lock(); // if(!m_stop) // m_stop = true; // m_mutex.unlock(); } int Worker::getData() { return m_data; } void Worker::stop(){ m_mutex.lock(); if(!m_stop) m_stop = true; m_mutex.unlock(); } void Worker::process() { m_stop = false; while(!m_stop) { doStuff(); QCoreApplication::processEvents(QEventLoop::AllEvents); // force the process of events among each iteration } emit finished(); } void Worker::doStuff() { // QMutexLocker locker(&m_mutex); // if necessary for security m_data = (m_data + 1) % 101; }
your_application constructor
... newThread = new QThread(); newWorker = new Worker(); newWorker->moveToThread(newThread); connect(newThread, &QThread::started, newWorker, &Worker::process); connect(newWorker, &Worker::finished, newWorker, &Worker::deleteLater); newThread->start(); // using signals to request and response data connect(newWorker, &Worker::responseData, [this](const int data){ qDebug() << "Data Received:" << data; }); QTimer::singleShot(5000, newWorker, &Worker::requestData); // or calling method from worker to return data int d; QMetaObject::invokeMethod(newWorker, "getData", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, d)); qDebug() << d; ...
your_application destructor
... newWorker->stop(); newThread->quit(); newThread->wait(); delete newThread; ...
-
@sykac said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
So if doStuff() was connected to a timer and wasn't in the while loop, it would work?
Yes.
And as you're mentioning thread safety and data manipulation - is this safe?
Is what safe? If you use the data from one thread only then it's safe, yes.
@KillerSmath said in QMetaObject::invokeMethod with BlockingQueuedConnection hangs forever:
Below is an example of how you can implement
Is the mutex really necessary to guard a simple boolean? I'd suggest substituting that with an atomic, even if Qt's mutex implementation is rather fast.