Domanda

problem

i'm currently putting FUSE together with qt5. there is no bridge between Qt and FUSE yet, both the FUSE main thread (which is spawning the other working FUSE threads) and the QCoreApplication are simply running side by side.

but i want to be able to send and receive data between a QObject based object and the pthread's Read(..) function shown in [0] using Qt's SIGNALS and SLOTS.

question

now i want to alter the Read(..) function from [0] to retrieve data using Qt's SIGNALS and SLOTS from a QObject based class. sending a signal from a pthread works but without an explicit QEventLoop i can't receive the reply. therefore i was looking at the code from [1] which is excellent in design but i didn't get it working yet.

pseudo code (taken from [1]):

QNetworkAccessManager qnam;
QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(...)));
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
/* reply has finished, use it */

looks interesting, all i would need is a QObject deriving class similar to the QNetworkReply which would handle the request.

when i was playing with that code i had the problem that my implementation of QNetworkReply wouldn't wait for loop.exec() to be running and then the finished() SIGNAL wouldn't be received by the loop.

but isn't there something easier than to spawn a QEventLoop?

NOTE: the QNetworkReply and QNetworkAccessManager in the example from [1] is spawned inside the pthread, i however, need to be able to communicate with the QCoreApplication's even queue using SIGNALS and SLOTS since the object with the data in it comes from a different QThread (in this either the QCoreApplication or a special QThread).

using a Qt::QueuedConnection

i've also found [2] and maybe:

connect(src, SIGNAL(signal-signature), dest, SLOT(slot-signature), Qt::QueuedConnection);

is all i want but i doubt that.

links

È stato utile?

Soluzione

What you're likely facing is that QNetworkAccessManager internally uses threads to process http requests. That's why it "doesn't wait" for you. There's a rather simple modification needed to fix it:

QNetworkAccessManager qnam;
QEventLoop loop;
QNetworkReply *reply = qnam.get(QNetworkRequest(QUrl(...)));
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
if (!reply->isFinished()) loop.exec();

Things to note when using QObjects in Multiple Threads

When the object that is the source of a signal lives (is instantiated in) a thread different than the thread of the object with slots, the connection will be of the QueuedConnection type automatically.

The real issue is: Each QObject has a thread affinity. The default affinity is the thread where the object was instantiated. You're not supposed to use such objects directly from other threads.

What you're likely doing is instantiating the sender and receiver objects in the same thread, but then emitting the signal from another thread. This is a source of potential errors error and leads to undefined behavior if the user of such an object is forcing a non-automatic direct connection.

Whenever you do emit object->signal(...), the following invariant should hold:

Q_ASSERT(QThread::currentThread() == object->thread());

Feel free to add those invariant checks in front of every emit() that you explicitly perform.

If the assertion fails, you need to use QObject::moveToThread to move the object to the thread where you want to fire its signals. You can get a QThread for a given pthread by calling QThread::currentThread() from the code that runs in the pthread. An instance of a QThread will be created automagically for you :)

Altri suggerimenti

Yes, you want the Qt::QueuedConnection method. But also ensure that you are using the multithreading Qt library. IIRC it is a build-time option.

See also: Qt documentation

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top