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?
Had to ad some code showing more what I ment:
pantheios::log(pantheios::debug, "BaseRequest(cancel) Request ", _id.toUtf8(), " canceled");
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.