QThread - Using a slot quit() to exit the thread - c++

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.

Related

Executing two thread in parallel with one thread containing an event

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.

How to inform threads to close on application quit with main event loop still spinning

This is a follow-up question to: QThread is creating a memory leak on application quit.
Basically, the solution of my question included something like this the destructors:
virtual ~MainWindow() {
delete th; // th = thread handler
QCoreApplication::processEvents(QEventLoop::AllEvents, 500);
}
virtual ~ThreadHandler() {
if (my_thread != Q_NULLPTR && my_thread->isRunning()) {
my_thread->quit();
my_thread->wait();
}
qDebug() << "ThreadHandler Destructor";
}
I don't like the "manual" event loop with processEvents, but without it, I have two memory leaks. Obviously, the main event loop isn't spinning anymore when the destructor of my MainWindow is called. So I moved the delete th; command to an aboutToQuit() slot in my MainWindow, but I still need the extra event loop at the end. If I had read the docs I would have known that the event loop stopped working just before this event.
This signal is emitted when the application is about to quit the main
event loop, e.g. when the event loop level drops to zero. This may
happen either after a call to quit() from inside the application or
when the user shuts down the entire desktop session.
Question:
Is there a way, to delete the ThreadHandler with the event loop still running at the end of the application? I mean, is there a signal like: "please post everything I have to do before quitting my job now"-signal?
Or is there another solution to solve this? The thread should work in the background the whole time, and is never "finished". There are signals to the thread, to give it new work, but on completion, the thread will just idle and not finish. This is intended.
I found this in the Qt forums. Chris Kawa:
Ideally you would wait for all the other threads to finish before you
quit the event loop in the main thread. If you can't do that for some
reason I would wait for other threads to finish in the aboutToQuit()
handler and then call processEvents() manually to process anything
these threads posted after you already quit the event loop.
Is this still right and there is no better solution?
I have a minimal, compilable, working example on git. It is a little bit too big to post, without cluttering everything with boring code.
Here is the key element: How do I setup the thread:
my_thread = new QThread;
ThreadClass *my_threaded_class = new ThreadClass();
my_threaded_class->moveToThread(my_thread);
// start and finish
QObject::connect(my_thread, &QThread::started, my_threaded_class, &ThreadClass::scanAll);
// https://stackoverflow.com/questions/53468408
QObject::connect(my_thread, &QThread::finished, my_threaded_class, &ThreadClass::stop);
// finish cascade
// https://stackoverflow.com/a/21597042/6411540
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
QObject::connect(my_threaded_class, &ThreadClass::destroyed, my_thread, &QThread::quit);
QObject::connect(my_thread, &QThread::finished, my_thread, &QThread::deleteLater);
my_thread->start();
As far as I can see, you're relying on the fact that the application is quitting to signal the background thread to quit, wait for it and then delete it. Why would you need deferred deletion in this case? I don't think that there is any reason to do so.
Since ThreadHandler is the class that creates, starts and ends your background thread, you should make it responsible to delete that thread too. Just add the following line in ThreadHandler destructor (after my_thread->quit(); and my_thread->wait()):
delete my_thread;
This should be safe, as the thread is guaranteed to have stopped beforehand. Also, since you are destroying your my_thread instance from the destructor, you should now remove this line from ThreadHandler::startThread():
QObject::connect(my_thread, &QThread::finished, my_thread, &QThread::deleteLater);
After that, you can go back to deleting your ThreadHandler instance from the MainWindow's destructor (without any hacks that involve neither aboutToQuit nor QApplication::processEvents).

Qt: Sending signal to dead/stopped thread

I've come across the problem, that I might be sending signals from one QThread to another, however I have no way of checking if the thread that is implementing the slot is running. How will the framework handle such a situation while using Qt::QueuedConnection ?
...
WorkerImp* pWorker = new WorkerImp();
QThread worker;
pWorker->moveToThread(&worker);
QObject::connect(&worker, QThread::finished, pWorker, &QObject::deleteLater, Qt::QueuedConnection);
bool connected = QObject::connect(this, &SlaveMaster::requireWork, pWorker, &WorkerImp::doWork, Qt::QueuedConnection);
assert(connected);
// at this point we have connected the signal, thread is not starded.
// however the object that we use to connect still exists and will after we exit the thread.
worker.start();
worker.exit();
worker.wait();
// note that when we exit the QThread we do not destroy the object - it can be start over
emit requireWork();
...
The signal is never handled. A queued connection across threads is posted as an event to the thread, handled by its event loop. If the thread is stopped (and thus its event loop), there is no one to pick up the event and deliver it:
From the Qt Docs Signals and Slots Across Threads:
Queued Connection: 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.
and Per-Thread Event Loop:
[...] If no event loop is running, events won't be delivered to the object.
Note that a blocking queued connection would dead-lock

QTimer not firing in a thread

I have an Qt5 c++ app with 2 threads, thread A is started when the main program starts up. The start method of thread A runs successfully.
So far so good. Next, in the main program I send a signal to Thread A to start a QTimer, which it does - but that timer never expires!
Thread B handles tcp connections. When I initiate a telnet connection to my app, thread B fires up and suddenly I see my Qtimer from thread A expiring at normal intervals.
Why is the QTimer from thread A not expiring until thread B starts?
I suspect my threads are getting messed up. note the last section of code below products this:
thread of this: QThread(0x200fe00)
thread of timer: QThread(0x1fff470)
Which suggest my worker object (this), is in a different thread from my timer object. This timer thread address is actually the MAIN thread. Why? I'm confused.
Suggestions?
In my main app I create and start my thread like this:
QThread * MyControllerThread = new QThread(this);
if (MyControllerThread) {
TheController *worker = new TheController(MyControllerThread);
if (worker) {
connect(MyControllerThread, SIGNAL(started()), worker, SLOT(start()));
connect(MyControllerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(MyControllerThread, SIGNAL(finished()), MyControllerThread, SLOT(deleteLater()));
worker->moveToThread(MyControllerThread);
MyControllerThread->start();
}
and in my main app I emit a signal to the new thread:
emit sig_startlocalpeer(Types::EActionLocalServiceStart); // Move the local peer to standby mode to start remote tests
which runs a slot in my thread (TheController object):
connect(&m_remotetestintervaltimer,SIGNAL(timeout()),this,SLOT(expiredRemoteTestIntervalTimer()));
m_remotetestintervaltimer.setTimerType(Qt::VeryCoarseTimer);
m_remotetestintervaltimer.start(REMOTETEST_TIMER_INTERVAL); // Wait between ticks
qDebug() << "thread of this: " << this->thread();
qDebug() << "thread of timer: " << m_remotetestintervaltimer.thread();
Well, it's not a Qt5 bug, it's more an inaccurate understanding of Qt's thread spirit.
In Qt, you have two ways to implement a thread which are using or not an even loop. Here is just a small visual example.
No event loop
myMethodCalledInANewThread
{
do{ ... }while(...);
}
With an event loop
myMethodCalledInANewThread
{
[...]
exec();
}
(Of course you can mix a do/while with an even loop but stay simple).
In QTimer's doc, you can read:
In multithreaded applications, you can use QTimer in any thread that
has an event loop. [...] Qt uses the timer's thread affinity to
determine which thread will emit the timeout() signal. Because of
this, you must start and stop the timer in its thread; it is not
possible to start a timer from another thread.
So I'm pretty sure you don't have a second event loop in your second thread and that's why you have the behaviour you described.
To give you some tips to be totally clear with thread using Qt, I suggest you to read:
QThread doc: https://doc.qt.io/qt-5/qthread.html
QTimer doc: https://doc.qt.io/qt-5/qtimer.html
and a very good article about how QThread implementation is misunderstood by a lot of users:
You're doing it wrong: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
I hope it will help ;)
The best answer seems to be a combination of RobbieE and Kuba:
You have to explicitly set the parent of the member variable in constructor. The parent-child feature is a Qt thing that exists among classes derived from QObject, it is not a feature of C++.
I never knew this - I assumed that when an object was created, its members variables automatically had their parent set to the object. Good to know!!

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.