How to abort all the requests of the QNetworkAccessManager
-
Hi
I'm currently working on an uploader with multiple files and I wish to be able to cancel all the ongoing calls. The structure of the app is the following.
I have a uploader that gets moved to a seperate thread. The uploader has a manager object that it allocates when it is in the thread. The manager has a QNetworkAccessManager. For every kind of request I do I have a special wrapper which I create that contains the request body and what kind of operation it wants to do. Also, the wrapper has a reference to the QNAM and does the request on it and also catches it when it is finished. Every wrapper object is either a child to the manager, or is allocated in a QScopedPointer.
Now, I would like to have a cancel button which will abort all the requests and destruct everything in the uploader. When that's done, the thread will be killed. My idea was to, in the wrapper desctructor call "this->_reply->abort()" followed by "this->_reply->deleteLater()". However, this caused me a lot of issue the "abort()" will send a "finished()" signal (which is not stated in the doc) and then I get an access violation. The way it crashes also depends if it is one of the wrappers that are located in a QScopedPointer or as a child to the manager. The issue should be that the QNAM deletes its children (QNetworkReply) since the wrappers take over the parentship of the replies so that they gets deleted with the wrapper.
So, my question is: if I delete the QNAM object, will all the current calls get aborted? If not, is there another way I could do this? Possible call the manager and tell it to abort all its children and when it's done, delete it.
Also, how do I handle the "finish()" signal that abort() emits?Thanks!
Edit:
Had to ad some code showing more what I ment:
@BaseRequest::~BaseRequest() {
if(_reply) {
if(_reply->isRunning()) {
pantheios::log(pantheios::debug, "BaseRequest(cancel) Request ", _id.toUtf8(), " canceled");
_reply->abort();
}
_reply->deleteLater();
}
}@When doing this on a QScopedPointer (which gets destroyed in the manager destructor) the stack looks like this:
@ QtCored4.dll!QObject::disconnect(const QObject * sender, const char * signal, const QObject * receiver, const char * method) Line 2891 + 0xc bytes C++
QtNetworkd4.dll!QNetworkReplyImpl::abort() Line 874 + 0x18 bytes C++FrameworkAzure.dll!BaseRequest::~BaseRequest() Line 126 C++
FrameworkAzure.dll!PutBlobRequest::~PutBlobRequest() Line 24 + 0x5e bytes C++@Where it crashes on line 2891 in QOBject:
@ const QMetaObject *smeta = sender->metaObject();@If however, the wrapper is a child to the manager (not too sure when it gets deleted then) I get this:
First a warning about "pure virtual function call" and if I click "retry" on the popup I get the following callstack and the message "myapp.exe has triggered a breakpoint"@ msvcr100d.dll!_NMSG_WRITE(int rterrnum) Line 217 C
msvcr100d.dll!_purecall() Line 54 + 0x7 bytes C
GreenButtonQtFrameworkAzure.dll!BaseRequest::handleFinishedRequest() Line 43 + 0x5 bytes C++
QtCored4.dll!QMetaObject::activate(QObject * sender, const QMetaObject * m, int local_signal_index, void * * argv) Line 3547 + 0x2e bytes C++
QtNetworkd4.dll!QNetworkReply::finished() Line 166 + 0x13 bytes C++
QtNetworkd4.dll!QNetworkReplyImplPrivate::finished() Line 796 C++
QtNetworkd4.dll!QNetworkReplyImpl::abort() Line 887 C++
@
If I remove abort() from the destructor I do not get an issue... but does it get aborted? Do not wanna risk it. -
The abort method aborts any upload in progress, about the finished() signal emitted you could just disconnect it before calling abort()
@ BaseRequest::~BaseRequest() {
if(_reply) {
if(_reply->isRunning()) {
disconnect(_reply,SIGNAL(finished()),PntToRecivingObject, SLOT(RecivingSlot()));
pantheios::log(pantheios::debug, "BaseRequest(cancel) Request ", _id.toUtf8(), " canceled");
_reply->abort();
}
_reply->deleteLater();
}
}
@
obviously you should change PntToRecivingObject and RecivingSlot() whit the corresponding pointer to signal receiver (this maybe?) and slot name -
that worked perfectly. cant belive i did not do that before. use disconnet() quite a bit.
thank you :)
(also, if anyone who writes the doc could actaully state that the abort() also sends a finish() signal, not just cancel() ?)
-
You get the finished() signal when the reply is finished, not just finished successfully or finished under your control. When you abort the reply you will almost certainly see the error() signal emitted, with OperationCanceledError, before finished(). Of course, the reply can fail for many other reasons. You should always check that the transfer finished successfully (QNetworkReply::error()) before doing anything that assumes the transfer was successful.
-
yeah. i surely do that. even parse the reply stream to get error responses aswell as catches every possible qt-error and log it, so that shouldnt be a problem. i just though that the abort() just killed it and that was that. just got a bit confused. read about cancel where they say that it emits a signal, but couldnt see that on the abort() until when i started debugging it and saw it in the call stack. so yeah. really nice to know :)
-
hi again... getting the same issue as before again.
have a look at this question: http://stackoverflow.com/questions/10440431/abort-reply-crashes-with-access-violation for more info. i have no idea what to do. the disconnect worked some times...