What is the parallelization mechanism in QNetworkAccessManager? - c++

I am writing an HTTP access module for VLC 2.0 using QtNetwork from Qt 4.7.4. My code snips follow:
static int Open(vlc_object_t *p_this)
{
....
QNetworkAccessManager *nam = new QNetworkAccessManager;
QNetworkReply *reply = nam->get(QNetworkRequest("http://stackoverflow.com/"));
Q_ASSERT(reply);
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit());
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()));
connect(reply, SIGNAL(readyRead()), &loop, SLOT(quit()));
loop.exec(); // -- BLOCKED HERE in Lion
....
}
The same code works well on Windows 7, but would get blocked on OS X Lion. The event loop after exec() never quit(). I also tried accessing reply->bytesAvailable() from another thread, which always returned 0. I guess the reason could be related to the parallel mechanism in QNetworkAccessManager, when nam couldn't get any time slots to work after the parent thread was blocked by QEventLoop.
Could anyone give me some suggestions why event loop would get blocked only on Mac, and what I could do to bypass such issue to make QNetworkAccessManager to work without creating another QThread?
BTW, the Qt being used is the latest version on macports built with Carbon framework (qt4-mac).

You may have to make periodic calls to QApplication::processEvents() to get the job done.

Related

Using QT events in the destructor of QApplication - hanging

I'm working with a QT GUI application which is having problems processing events during the QApplicaton destructor. A library I use (that I can't change) uses a QEventLoop. It has written some data to a socket and seems to be waiting for a response. The debugger shows that QEventDispatcherWin32::processEvents is looping and using up CPU.
I've managed to get it to work by deleting some particular widgets earlier on. However, this seems a bit random!
We are logging off our server when a widget is destroyed. Depending on what widgets are created, I sometimes get the hang and sometimes don't.
This is the exec call that hangs -
m_timedout = false;
QEventLoop loop;
QTimer timer;
timer.setSingleShot(true);
connect(&timer, SIGNAL(timeout()), this, SLOT(slt_timeout()));
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
timer.start(1800000);
connect(this, SIGNAL(sig_response(int, int, QByteArray)), &timer, SLOT(stop()));
connect(this, SIGNAL(sig_response(int, int, QByteArray)), &loop, SLOT(quit()));
loop.exec(QEventLoop::ExcludeUserInputEvents);
So what am I asking? I'm very new to QT and don't understand all the concepts but it sounds worrying to me that we are relying on QT event processing during the destructor of the application. Is that a valid thing to do? Won't QT have started to wind down?
Is there anything else that would cause that hang?

Qt: connect a signal after a request is sent in QNetworkAccessManager [duplicate]

This question already has an answer here:
Qt signal slot connection - QNetworkAccessManager
(1 answer)
Closed 7 years ago.
I was checking some simple examples of using QNetworkAccessManager and I found this (Assuming that manager is a QNetworkAccessManager:
QNetworkRequest request;
request.setUrl(QUrl("http://www.someserver.com"));
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(slotSslErrors(QList<QSslError>)));
As far as I understand, the call to manager->get will send out a GET request. The slots to handle the answer to that request, however, are connected only after the call is sent, which does not seems to make sense for me. Here my question:
isn't it a problem to connect the slots to the signals after the request is done? Can it happen that the request is done and the signals are emitted before the connection takes place, and hence, that the signals are missed and never processed by the corresponding slots?
Thanks!
L.
UPDATE: As pointed out by cyber_raj, this question has been already answered here: Qt signal slot connection - QNetworkAccessManager
Not a problem.
The get call is asynchronous:
http://doc.qt.io/qt-5/qnetworkaccessmanager.html#details
QNetworkAccessManager queues the requests it receives, and runs 6 asynchronous tasks per time.
So there's no much room to an error as you point.
But if you're afraid you can try the first example, connecting the signals of the manager:
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(replyFinished(QNetworkReply*)));
manager->get(QNetworkRequest(QUrl("http://qt-project.org")));

Use signals and slots in console application?

In my project, I need to download a 1.5MB file from a server. I was able to achieve this in my GUI application like this:
QNetworkAccessManager* m_NetworkMngr = new QNetworkAccessManager(this);
QNetworkReply *reply = m_NetworkMngr->get(QNetworkRequest(QUrl("someurl.com")));
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
QUrl aUrl("someurl.com");
QFileInfo fileInfo=aUrl.path();
QFile file(aPathInClient+"\\"+fileInfo.fileName());//aPathInClient is predefined
file.open(QIODevice::WriteOnly);
file.write(reply->readAll());
delete reply;
I am getting the following error:
'connect' function does not take four arguments.
How can I modify the signals and slots to work in my console application?
My guess is that your code is correct with regards to establishing signal/slot connection, however compiler seems to be confused because of the connect() function name and cannot resolve it properly: whether it is QObject::connect() that takes at least 4 arguments, or it is another function with the same name, but different signature. I would suggest to try to explicitly tell compiler which function to use, i.e.:
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));

pthread 2 signals and slots wrapper mit QEventLoop

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
[0] https://github.com/qknight/qt-fuse-example/blob/4d92a74fad22fd559588e58be67f766174c7efb8/qt-fuse/examplefs.cc#L74
[1] http://qt-project.org/wiki/ThreadsEventsQObjects#7494f2b4836907fc1c09311e3a0305e6
[2] emit Qt signal from non Qt Thread or ouside Qt main event loop with at 4.5
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 :)
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

Process Signals & Slots Using a Thread

I need to be able make a request GET request, which requires the use of signals to process the replies, and return the reply back in a a processed form. I've structured the code as described in Threading Wihtout the Headache, but when I run the reply is never received or processed.
// Set-up request
QNetworkAccessManager* pConnection(new QNetworkAccessManager());
connect(pConnection,
SIGNAL(finished(QNetworkReply*)),
this,
SLOT(process(QNetworkReply*)));
QUrl url;
url.setUrl(HOST);
url.addQueryItem("P1", "Hi");
url.addQueryItem("P2", "Bob");
// Send request
QNetworkRequest request(url);
pConnection->get(request);
// Wait for reply
QThread* pResponce(new QThread(this));
connect(this,
SIGNAL(processingFinished()),
pResponce,
SLOT(quit()));
pConnection->moveToThread(pResponce);
pResponce->start();
pResponce->wait();
pConnection->deleteLater();
pResponce->deleteLater();
return this->processedReply;
Obviously I'm missing something, but what? It works when I'm not using the threads (and the deletes), so it's not the URL or server.
Only the main/gui thread receives signals if you don't set up an event loop in the other threads.
If no event loop is running, events won't be delivered to the object. For example, if you create a QTimer object in a thread but never call exec(), the QTimer will never emit its timeout() signal. Calling deleteLater() won't work either. (These restrictions apply to the main thread as well.)
Source: http://doc.qt.digia.com/4.6/threads-qobject.html
See QThread::exec(). That's why in the example you're linking the QThreadEx class is introduced, and used (not in your code snipplet, though!)...