Properly delete QThread - c++

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()));

Related

Multi-threads cause the runtime error in Qt

When I am trying to do multi-threads in Qt, for example:
If I create a class object in another class like this:
QThread thread;
Worker worker;
worker.moveToThread(thread);
it will cause the runtime error when I close the program.
But if I create the class object by pointer like this:
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
it will be no error. Why do I have to do like this?
And do I have to delete the pointer after using? If I do not, will that cause the memory leak? I see a lot of tutorials delete them like this:
connect(worker, SIGNAL (finished()), thread, SLOT (quit()));
connect(worker, SIGNAL (finished()), worker, SLOT (deleteLater()));
connect(thread, SIGNAL (finished()), thread, SLOT (deleteLater()));
Qt typically manages the memory of its objects. Lots of the documentation says this, but not all of it.
Your runtime error is caused by a double-delete. In the first example, when worker goes out of scope it will be destructed, and Qt will also attempt to delete it. In the second example, only Qt deletes it, and you do not.
If you look towards Qt's own documentation of this, you can see them doing the same thing:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
...
} // notice worker was not cleaned up here, which implies moveToThread takes ownership
However, moveToThread's documentation isn't clear on this.

Qthread - sleep till event

I want a thread that sleeps as long as a signal is triggered in my programm.
I created a Qthread and added my class to it
QThread* serialthread = new QThread;
Serial* serial = new Serial();
serial->moveToThread(serialthread);
connect(serial, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(serialthread, SIGNAL(started()), serial, SLOT(process));
connect(serial, SIGNAL(finished()), serialthread, SLOT(quit()));
connect(serial, SIGNAL(finished()), serial, SLOT(deleteLater()));
connect(serialthread, SIGNAL(finished()), serialthread, SLOT(deleteLater()));
serialthread->start();
The function serial::sendRequest() of my class should be triggered by a signal.
The other time I want the thread so sleep without wasting CPU-Time.
The thread is already sleeping and not wasting any CPU time when there's no work for it to do. You don't need to do anything special to get that behavior. It's how the default implementation of QThread::run behaves: it starts an event loop. When the event loop has no events to handle, it sleeps, waiting for more events.

How to Avoid Qt Access Violation Errors When Using QThread?

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.

Qt C++ how stop thread if moveToThread

After lots of experimentation and learning from stackoverflow, I've create a QObject worker, a QThread, and moved my QObject worker to my QThread, and started the QThread - and it's working!
void TelnetServer::incomingConnection(qintptr socketDescriptor)
{
QThread * TelnetConnectionThread = new QThread(this);
TelnetConnection *worker = new TelnetConnection(socketDescriptor,TelnetConnectionThread);
connect(TelnetConnectionThread, SIGNAL(started()), worker, SLOT(start()));
connect(TelnetConnectionThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
worker->moveToThread(TelnetConnectionThread);
TelnetConnectionThread->start(); // Start the thread running
}
I assume that calling TelnetConnectionThread->start() starts the eventloop within the QThread (since it seems to be running). Now the problem...how do I stop the thread? I tried:
QThread::quit();
but the thread is still running when I shutdown the app. Does this mean the exec loop is not running? Do I have to do something else to stop this thread? Or is it actually stopped but just not deleted?
It's a bad idea to kill running thread, from design and technical points of view.
Usually the thread must own the decision to quit based on "terminate" flag. For example create new flag "stop", if quit() slot is signaled mark the flag true. In a thread function verify the flag periodically and if it's true - exit thread function.

How do I process events on a QThread?

Normally if I am in a process intensive function I can call QCoreApplication::processEvents() or QEventLoop::processEvents() to ensure that my processing doesn't block other signals and slots.
However, if I create a new QThread and move a worker to that thread, then I don't have a QCoreApplication or a QEventLoop with which to call processEvents().
From my research, it seems that I should be able to install a QEventLoop on the new QThread I created, and then I can call processEvents() on that QEventLoop.
However, I can't figure out how to do this. I figure it might look something like this:
QThread *thread = new QThread(this);
Worker *worker = new Worker(this);
QEventLoop *loop = new QEventLoop();
connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(started()), worker, SLOT(startProcessing()));
connect(worker, SIGNAL(done()), thread, SLOT(quit()));
connect(worker, SIGNAL(done()), loop, SLOT(quit()));
worker->moveToThread(thread);
//loop->exec() // blocks processing of this thread
loop->moveToThread(thread);
//loop->exec() // loop is not a member of this thread anymore and even
// if it was, this would block the thread from starting
thread->start();
//loop->exec(); // loop is not a member of this thread anymore and even
// if it was, this would block this thread from continuing
Every place I try to start the loop has some sort of issue. But even if something like this worked, how would I call processEvents() on that QEventLoop()?
Alternatively, QThread also has a function setEventDispatcher() and QAbstractEventDispatcher has a processEvents() function, but I can't seem to find anything that subclasses QAbstractEventDispatcher.
What is the proper way to process events during an intensive worker function on a QThread?
According to the documentation, calling QCoreApplication::processEvents() processes events for whichever thread called it.
However, if I create a new QThread and move a worker to that thread, then I don't have a QCoreApplication or a QEventLoop with which to call processEvents().
Exactly - don't call it. You don't need it, you don't want it.