Using QT events in the destructor of QApplication - hanging - c++

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?

Related

How to use QTimer for non-ui task in QT?

In my QT project I want to do a non ui activity; which is sending files to server every 60 minutes.
I tried using QTimer for it and for that QCoreApplication instance is also needed.
The timer does start and call the upload function periodically but it keeps QCoreApplication hostage (unable to delete it as timer would be running infinitely) and ultimately application crashes.
I tried to move QTimer to another thread, but that also doesn't solve the issue as app is still running in main thread.
Below is code of function which is called from __stdcall function loaded during dll initialization.
{
int argc=0;
QCoreApplication app(argc, nullptr);
QThread* newThread = new QThread(this);
QTimer *timer = new QTimer(0);
timer->setInterval(60*60*1000);
timer->moveToThread(newThread);
QObject::connect(timer, SIGNAL(timeout()), this, SLOT(uploadFiles()), Qt::DirectConnection);
timer->connect(newThread, SIGNAL(started()), SLOT(start()));
newThread->start();
app.exec();
}
Maybe this is not best approach to do it . Need guidance on how to achieve it.
Update:
Figured out that Qtimer is definitely not ideal way to achieve it.
I was able to perform periodic execution using std::thread and atomic.

Qt: Program not responding despite separate thread

I have a program written with C++/Qt converting certain game files. This is the first time I've done something like this, so I'm not particularly experienced yet. I've had issues with the window occasionally showing the "Not responding..." message. After reading up on it, the problem seemed to be that the processing was done in the main thread, blocking the gui.
So I tried running a separate thread for the actual work being done, however the problem still occurs.
Here's the section creating the extra thread:
QThread* thread = new QThread;
WKConverter* converter = new WKConverter(settings);
converter->moveToThread(thread);
connect(converter, SIGNAL(log(std::string)), this, SLOT(log(std::string)));
connect(converter, SIGNAL(setInfo(std::string)), this, SLOT(setInfo(std::string)));
connect(converter, SIGNAL(createDialog(std::string)), this, SLOT(createDialog(std::string)));
connect(converter, SIGNAL(createDialog(std::string, std::string)), this, SLOT(createDialog(std::string, std::string)));
connect(converter, SIGNAL(createDialog(std::string, std::string, std::string)), this, SLOT(createDialog(std::string, std::string, std::string)));
connect(converter, SIGNAL(setProgress(int)), this, SLOT(setProgress(int)));
connect(converter, SIGNAL(increaseProgress(int)), this, SLOT(increaseProgress(int)));
connect(thread, SIGNAL(started()), converter, SLOT(run(bool)));
connect(converter, SIGNAL(finished()), thread, SLOT(quit()));
connect(converter, SIGNAL(finished()), converter, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
converter->run();
With signals/slots to push updates for a progress bar and a label indicating what's being worked on to the gui. Generally this works, but as said I still encounter the "Not responding..." issue (Though interestingly, this doesn't seem to happen if I'm debugging with Qt Creator, only when running the compiled exe afterwards)
Have I missed something? Is there something else I need to do? I would appreciate any pointers.
If it helps, here is the github for the project, though I have not pushed the work done on threading there yet: https://github.com/Jineapple/WololoKingdoms

Queue several QTimers calls to slots

I'm using a library where I need to call a trigger function that starts some processing (starts a thread that does the job) and returns immediatly. Then when the processing is finished a signal is emitted.
This needs to be done periodically based on different parameters. Since other calls to the trigger function must not be done while processing I would need to queue them in some way. I thought about using a QEventLoop ("loop") but without luck so far.
Please look at this piece of code:
test::test()
{
connect(&timer, SIGNAL(timeout()), this, SLOT(timerSlot()));
connect(&timer2, SIGNAL(timeout()), this, SLOT(timer2Slot()));
connect(&library, SIGNAL(processingFinished()), &loop, SLOT(quit()));
timer.setInterval(2000);
timer.start();
timer2.setInterval(4000);
timer2.start();
}
void test::timerSlot()
{
loop.exec();
startProcessing(some_parameters);
}
void test::timer2Slot()
{
loop.exec();
startProcessing(some_other_parameters);
}
The issue is that when loop.exec() is called while processing I get the message:
QEventLoop::exec: instance xxxxxx has already called exec()
What would be the right way to do what I intend?
Thanks in advance.
One simple solution is to introduce a member variable, for example, bool m_isProcessing, start processing only if m_isProcess == false, then set it to true when you start processing and reset it to false when processing is complete. Since the slots for your test QObject execute on the GUI/main thread, you don't need to worry about synchronization between timer slots and the slot that will execute when processing is finished.
If you want to keep track of events that occur during processing, you can use the same method: introduce a member variable to the test class to track the information you need.
It seems that you are looking for Qt::QueuedConnection.
Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
Therefore, you could write something like this:
connect(&timer, SIGNAL(timeout()), SLOT(timerSlot()), Qt::QueuedConnection);
connect(&timer2, SIGNAL(timeout()), SLOT(timer2Slot()), Qt::QueuedConnection);
For details, you could look into the well-known mandelbrot example how this is done in there, although it is using worker threads:
Mandelbrot Example

Thread count increases a lot, even when deleting the threads

Have an application where I have QOBJects which all contain an QNetworkAccessManager. I am aware of that it's suggested to only have on per application but since I'm making a lot more that 6 calls at the same time, I needed to have it like this. So, this is how I start the threads.
FileUploader *fileUploader = new FileUploader(_fileList);
QThread *fileUploaderThread = new QThread();
fileUploader->moveToThread(fileUploaderThread);
// uploader > model
connect(fileUploader, SIGNAL(progressChangedAt(int)), _model, SLOT(reportProgressChanged(int)), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(statusChangedAt(int)), _model, SLOT(reportStatusChanged(int)), Qt::QueuedConnection);
// uploader > its thread
connect(fileUploader, SIGNAL(canceled()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(finished()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection);
// uploader > this
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(finishedCurrentUpload()), this, SLOT(uploadNextFileOrFinish()), Qt::QueuedConnection);
// thread > this
connect(fileUploaderThread, SIGNAL(finished()), this, SLOT(checkIfAllThreadsAreFinished()), Qt::QueuedConnection);
connect(fileUploaderThread, SIGNAL(finished()), this, SLOT(deleteFinishedThread()), Qt::QueuedConnection);
// this > uploader
connect(this, SIGNAL(cancel()), fileUploader, SLOT(cancel()), Qt::QueuedConnection);
fileUploaderThread->start();
QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection);
QMetaObject::invokeMethod(fileUploader, "uploadAt", Qt::QueuedConnection, Q_ARG(int, startIndex));
QMutexLocker locker(&_mutex);
_threadCount++;
Every thread starts out with an index to a list so that they can fetch the thing they need to upload and proceed about 5 steps (calls with the QNetworkAccessManager). When there's no more items to upload, the fileUploader signals "finished()" which calls the deleteFinishedThread and deleteFinishedUploader where I do:
QThread *thread = qobject_cast<QThread*>(sender());
if(thread != NULL) thread->deleteLater();
or
FileUploader *fileUploader = qobject_cast<FileUploader*>(sender());
if(fileUploader != NULL) fileUploader->deleteLater();
These are suppose to delete the threads when they are done.
The issue is that every time I start (for example) 3 threads that have 1 file to upload and handle each, the thread count gets increased by 8-10. This means that the thread count goes from about 5 to 100 if I restart the uploading process a few times.
What am I doing wrong? Or is my biggest issue that I use "Windows Task Manager" to control this? I am handeling all replies from the QNAM which I delete and everything seems to get deleted, but still I scratching my head when the threadcount keeps increasing...
EDIT:
In my fileuploader I create an object(Manager) on the heap which has a QNetworkAccessManager on the stack. When the fileuploader gets deleted it calls "deleteLater()" on the Manager but it never gets deleted. We tried to delete the Manager and set it to NULL but that gave us an access violation since the Manager wasn't done yet (the QNetwork.dll reported the issue so it must be something inside the QNAM that is running still). The times when we didnt get access violation, the object was deleted and the thread count went back to normal. What can live inside the QNAM and prevent me from deleting it when it goes out of scope? Should I create the QNAM on the heap instead? At this stage non of the destructors are being called even when calling deleteLater()...
Also, how do I reduce the handle-count?
I might be wrong, but I think there is a problem with your signals:
// uploader > its thread
connect(fileUploader, SIGNAL(canceled()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(finished()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection);
// uploader > this
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection);
Remember that when multiple slots are connected to the same signal, they're executed in the order of connection. Here, when the fileUploader will be finished, it will call finished() which will first call the quit() method of the thread, and then the deleteFinishedUploader() method. Same for the canceled() signal.
But, meanwhile, the thread was finished, so no event processing for the fileUploader can be done (consequence of the moveToThread(...)). deleteLater() needs event processing, thus your fileUploader will never be deleted...
I am not 100% that arranging your connections in the other way will get things working: the deleteLater() can be called and the thread exited immediatelly after, without event processing.
The solution might be to re-moveToThread() the fileUploader to the main thread, or to a thread which still processes its event loop.
Not an answer but :
fileUploaderThread->start();
QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection);
QMetaObject::invokeMethod(fileUploader, "uploadAt", Qt::QueuedConnection, Q_ARG(int, startIndex));
means you start the even loop, and then you queue up slots or signals to be executed.. Assume (in general) that there are other QObject in this thread. It might be possible that these get their slots or signals executed because the event loop has already started. If you want the "init" and "uploadAt" to be the first methods to be invoked when the event loop run, you queue them before starting the event loop (If the thread is not started they are never going to be executed).
From QMetaObject::invokeMethod:
If type is Qt::QueuedConnection, a QEvent will be sent and the member is invoked as soon as the application enters the main event loop.
In this case the event is sent to the thread event loop.
After a lot of "almost giving up" I came up with a solution for the threads. It is true what Synxis said about the order of the slots.
I still however have some issue with the filehandles, and if someone has a better answer that mine I'm happy to accept that.
I changed my code to:
...
// uploader > this
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection);
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection);
// uploader > its thread
connect(fileUploader, SIGNAL(destroyed()), fileUploaderThread, SLOT(quit()));
This means that the thread gets stopped (quit()) when the object is getting deleted. This actually works even though the documentation states:
This signal is emitted immediately before the object obj is destroyed, and can not be blocked.
All the objects's children are destroyed immediately after this signal is emitted.
Which means that this signals gets emitted just BEFORE anything gets destroyed (which would mean that I would quit the thread before the uploader in it got deleted)? Not really good enough and it might be a better way. HOWEVER, atm, my thread count goes down quite a bit every time the uploader finishes and back to normal after a 20sec or so (a few "watcher-threads" must be killed by windows etc).

What is the parallelization mechanism in QNetworkAccessManager?

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.