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).
Related
I have two functions which has to be executed after specific interval of time. So I create two threads and each function is executed in separate threads. One of the function "checkForEvent()" has a Event which is waiting for an event to happen.
When the "checkForEvent()" function is waiting for an event the other function "checkServer()" is not being executed even though it is run in a separate thread.
dongleThread = new QThread(this);
checkDongle = new QTimer();
checkDongle->setInterval(DONGLE_CHECK_TIMER);
checkDongle->moveToThread(dongleThread);
connect(checkDongle, SIGNAL(timeout()), this, SLOT(checkForEvent()));
connect(dongleThread, SIGNAL(started()), checkDongle, SLOT(start()));
dongleThread->start();
serverThread = new QThread(this);
checkServer = new QTimer();
checkServer->setInterval(SERVER_CHECK_TIMER);
checkServer->moveToThread(serverThread);
connect(checkServer, SIGNAL(timeout()), this, SLOT(checkServer()));
connect(serverThread, SIGNAL(started()), checkServer, SLOT(start()));
serverThread->start();
checkForEvent() //This function is waiting for an Event
checkServer()
How can I execute both the functions in separate threads ?
Thank you!!
Your connect call uses the default connection type: Qt::AutoConnection. Here is what this means:
Qt::AutoConnection: If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
Here your QTimer and this are in a different thread. It means Qt::QueuedConnection will be used.
Qt::QueuedConnection: 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.
So your two slots are called in the thread of this. If one is blocking, the other one will never run.
One way of fixing the problem is having a worker object moved to its own thread. The worker object would call checkForEvent and emit a signal after the wait is over. This signal can be connected to checkServer in this. With this, you need only one thread. You can look at the documentation of QThread for more information about worker objects.
I'm new to QT and I'm trying to create and destroy a QThread upon button click (potentially multiple times). I've read through a lot of posts but my Thread either didn't get destroyed or caused a untraceable heap exception within the QMain.dll.
I create my Thread like this:
thread = new QThread;
reader = new Reader(); //a QObject subclass
reader->moveToThread(thread);
connect(thread, SIGNAL(started()), reader, SLOT(read()));
connect(reader, SIGNAL(timeout()), this, SLOT(threadTimeout()));
connect(reader, SIGNAL(finished()), reader, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(threadFinished()));
The Thread then runs in a loop and sends data. The read() function looks like this:
void Reader::read() {
while(!stop) {
//... do something ...
}
emit finished();
}
On Button click I call
reader->setStop(true);
which breaks the Thread's while-loop. The finished signal is emitted but then a memory exception is triggered. If I remove the two deleteLater() slots no exception is raised but the thread is (obviously) not deleted.
Am I doing something wrong here? Thanks in advance.
The main issue is that you are deleting the thread object (ie the QThread) while the thread of execution is running. In your threadFinished(), which is actually task finished, you need to do :
thread->quit();
thread->wait();
thread->deleteLater();
reader->deleteLater();
and remove the finished -> deleteLater connections.
Try to add connection like this one for leaving thread event loop.
connect(reader, SIGNAL(finished()), thread, SLOT(quit()));
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
I am working on an application where I use QThread to capture frames of camera (OpenCV). I followed the approach described here and moved a worker to the QThread:
m_CameraCaptureThread= new QThread();
m_ProcessingThread= new QThread();
m_CameraCapture= new CCameraCapture();
//Move camera capture object to thread
m_CameraCapture->moveToThread(m_CameraCaptureThread);
//Connect error signal
QObject::connect(m_CameraCapture, SIGNAL(error(QString,QString)), this, SLOT(reportError(QString,QString)));
//Connect the finished signal of the worker class to the thread for quitting the loop
QObject::connect(m_CameraCapture, SIGNAL(finished()), m_CameraCaptureThread, SLOT(quit()));
//This connections guarantees that the *m_CVideoCapture is automatically deleted if the event loop of the thread is terminated. Therefore, m_CVideoCapture does not need to be released manually if the capturing process is stopped.
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCaptureThread, SLOT(deleteLater()));
QObject::connect(m_CameraCapture, SIGNAL(finished()), m_CameraCapture, SLOT(deleteLater()));
QObject::connect(this, SIGNAL(exitThreads()), m_CameraCapture, SLOT(exitThread()));
This code is part of the constructor of my camera handler class. If the main application is closed I want to exit all threads. Therefore, the destructor of my CCameraHandler is:
CCameraHandler::~CCameraHandler(void)
{
emit exitThreads();
qDebug() << "CCameraHandler deleted";
}
The exit Slot in my camera capture which is called by the signal exitThreads() is:
void CCameraCapture::exitThread(){
//Stop grabbing
stopGrabbing();
//Emit finished signal which should be connected to quit() of QThread and deleteLate of this class;
emit finished();
}
As one can see from the connection setup the emitted finished() signal will quit the event loop of the thread and call deleteLater() of the Worker and the Thread. The destructor of the worker which is called looks like:
CCameraCapture::~CCameraCapture(void)
{
qDebug() << "CCameraCapture deleted";
}
The result is that the Destructor of CCameraCapture is called correctly - it appears only one time in the QDebug stream but at the end of CCameraCapture::~CCameraCapture(void) scope. I get an access violation error from OpenCVs opencv_highgui249d.dll. As I am only using:
cv::VideoCapture m_Cap;
in the class definition of CCameraCapture, the destruction of m_Cap must cause this error. At the moment I really do not know how to solve this issue. Any ideas?
Edit:
The application should close when the main window is closed using
this->setAttribute(Qt::WA_DeleteOnClose);
and
CMainWindow::~CMainWindow(){
m_CameraHandler->deleteLater();
m_ImageWidget->deleteLater();
m_ProcessedImageWidget->deleteLater();
emit windowClosed();
qDebug() << "CMainWindow deleted";
}
If the main application is closed I want to exit all threads.
Without debugging this myself, it looks like a problem here is the emit in the destructor of CCameraHandler.
One reason this is problematic is that if the user closes the application and it quits the main event loop, (started with QApplication's call to exec), any objects that have had deleteLater called may not actually be deleted. In this case, I'm specifically looking at m_CameraCaptureThread.
If we walk through the event handling of signals / slots: -
QApplication::processEvents...
CCameraCapture::exitThread()
emit finished
QThread::quit
QThread::deleteLater
By calling deleteLater, an event is placed in the current thread's event queue to process the delete after the slot function has exited. This occurs when the event loop next processes events.
However, the application is going to quit, so the event loop does not run again and the call to deleteLater is not serviced.
If all objects are running in the same thread, then signal / slot connections are direct, which would be less of an issue. However, with multiple threads, the connections are queued.
I suggest changing the destructor so that you clean up without using an emit signal here and see if the problem still persists.
Finally solved the problem: The application terminated before the threads left their eventloop. The point that a camera capture thread usually never terminates makes it necessary to exit the capturing loop at some point. If this exit is triggered by closing the application one needs to exit the threads before the application closes. I follow this example (see above). However, as the loop never terminates one needs emit a signal from the main thread to terminate. If this is done on close of the application, the signal will not arrive in time. Therefore, I connected the finished() signal of QThread to the deleteLater() of the worker
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCapture, SLOT(deleteLater()));
QObject::connect(m_CameraCaptureThread, SIGNAL(finished()), m_CameraCaptureThread, SLOT(deleteLater()));
The finished signal will be emitted on exit of the event loop and will delete the QThread and the worker. In the destructor of the class which sets up the QThread and the worker I now use
CCameraHandler::~CCameraHandler(void)
{
emit stopGrabbing();
m_CameraCaptureThread->exit();
m_CameraCaptureThread->wait();
qDebug() << "CCameraHandler deleted";
}
At first I left out the wait and the application still crashed. For me this solved the problem. Thanks for the help to figure out this solution.
I want to inform an object when a thread has finished running. However, I cannot get the thread to exit properly. I have the following code:
Processor.cpp
thread = new QThread;
tw = new ThreadWorker;
connect(tw, SIGNAL(updateStatus(QString)), this, SLOT(statusUpdate(QString)));
tw->doSetup(thread, strDic);
tw->moveToThread(thread);
thread->start();
while(thread->isRunning())
{
}
qDebug() << "Thread Finished";
ThreadWorker.cpp
void ThreadWorker::doSetup(QThread *thread, const string &path)
{
_strPath = path;
connect(thread, SIGNAL(started()), this, SLOT(run()));
connect(this, SIGNAL(finished()), thread, SLOT(quit())); //tried terminate() also
}
void ThreadWorker::run()
{
DirectorySearch dicSearch;
vector<string> vecFileList = dicSearch.getFileList(_strPath);
emit updateStatus("Directory Fetched");
emit finished();
}
The quit() slot does not seem to stop the thread (QThread::isFinished never returns true). Can someone guide me in the right direction?
(Note: ThreadWorker does not inherit from QThread)
Assuming that Processor.cpp is running in your main thread, the while(thread->isRunning()) loop has your main thread completely tied up. This means that your application's event loop cannot do any processing so the signalupdateStatus() for example, will never get processed. As mentioned in the comments, since the QThread object is created by the main thread, its signals won't work either since they will also require the main event loop to be doing its thing. Besides, if you are waiting in your main thread for your worker thread to do something, why use a worker thread at all? :)
Try removing the while loop, add a slot workDone() (or whatever you want to call it) to Processor.cpp and connect that to your Threadworker's finished() signal.
I had the same problem and found the answer. Here is my question:
What is the use of QThread.wait() function?
To solve your problem, you don't need to run the QCoreApplication::instance()->processEvents() in your while loop, what you need to do is, instead of invoking the quit() which tries to send a signal to your creating thread's event loop (which is now blocked by the while loop), you have to call it directly.
So for your code, drop the line:
connect(this, SIGNAL(finished()), thread, SLOT(quit())); //tried terminate() also
And instead of:
emit finished();
Use:
this->thread()->quit();
Tada... problem solved. Lesson learned: don't try to exit a worker thread by the qt signal-slot mechanism from within it, because your signals do not end up where they are supposed to (your worker thread's event loop), but they end up in the creating thread instead. You never know what that thread is doing, and if its event loop is running or not, and this shouldn't be of business to your worker thread anyways... Instead, call the quit directly.
You can use Qt::DirectConnection:
connect(this, SIGNAL(finished()), thread, SLOT(quit()), Qt::DirectConnection);
This stops the thread.
Instead of doing your 'doSetup' function... before you moveToThread, setup connections between SINGALS on tw's parent and SLOTS in tw.
I would do 4 connections.
First is to the run method in ThreadWorker. Thats simple and self explainatory enough.
Second is from your finished signal to the third SIGNAL connection below. A SIGNAL that quits the thread
Third to a SIGNAL that should call the terminate() slot of the thread. This will effectively close the event loop setup when you connect to the run method (exec is auto called when you do a start()) and since your run method isn't a loop of some sort, will close the thread without issue.
Forth is from the thread's terminated() SIGNAL to a SLOT in tw's parent. This will show you when the thread is dead if you want to do something at that point.
You do the above connections (if you need to pass in the string, add a variable to the run method and corresponding SIGNAL connection and you'll have the data), move to thread, thread start, then do the SIGNAL attached to the run method. Let it do its thing. When its finished, it will do a finished signal that gets tied to another signal that gets tied to the threads terminated slot. This will kill the event loop and exit the thread, pushing a terminated signal out so you can then do something.