QThread: slot quit() is never invoked and hence the thread wait() is forever - c++

I have the exact same problem as described QThread won't stop / does not process a signal but with a twist. I cannot get it to work even with QCoreApplication::processEvents() to my while loop. I followed this blog post and ended up like as follows:
MediaController.cpp
void MediaController::buttonPlayClicked(bool checked)
{
if (checked)
{
m_loopThread = new QThread;
m_playPauseworker = new PlayPauseWorker;
m_playPauseworker->moveToThread(m_loopThread);
connect(m_playPauseworker, &PlayPauseWorker::dataReady, this, &MediaController::onDataReady);
connect(m_loopThread, &QThread::started, m_playPauseworker, &PlayPauseWorker::process);
connect(m_playPauseworker, &PlayPauseWorker::finished, m_loopThread, &QThread::quit); // <-- never works
connect(m_playPauseworker, &PlayPauseWorker::finished, m_playPauseworker, &PlayPauseWorker::deleteLater);
connect(m_loopThread, &QThread::finished, m_loopThread, &QThread::deleteLater);
m_loopThread->start();
}
else
{
m_loopThread->requestInterruption();
}
}
The above slot is called every time play/pause checkable button is clicked. Thread and worker are created on the main thread.
PlayPauseWorker.cpp
void PlayPauseWorker::process()
{
while (!QThread::currentThread()->isInterruptionRequested())
{
// heavy computations
emit dataReady(std::tuple<QImage, QImage, QImage>>); // <-- works!
QCoreApplication::processEvents(); // <-- doesn't help with quit()
}
emit finished(); // <-- emits the signal but quit() not called
}
On further processing, when i access wait() to see if my thread has exited, it never returns.
In addition to quit() slot never called, i noticed my GUI becomes very choppy when the thread is running. I sometimes can/cannot click on other buttons or play with UI. I went through a lot of SO posts but couldn't figure out a way to cleanly exit the thread whenever i need to. Not sure where am i going wrong.

After trying out a lot of suggestions i still couldn't figure out why emit finished() doesn't quit the thread. So, as a last resort, i used this->thread->quit() to achieve the same.
But thanks to all the commenters here, i narrowed down on laggy/choppy gui issue.
My emit data(std::tuple<QImage, QImage, QImage>>) was setting pixmap on QGraphicsScene on a loop without removing the already set pixmap on the scene leading to huge memory leak and ultimately crash.

Related

Destroying thread and exiting loop

I'm creating a thread like this:
main.cpp
QThread acceptorThread;
acceptorObject acceptorobject;
acceptorobject.setupConnections(acceptorThread, simulation);
acceptorobject.moveToThread(&acceptorThread);
acceptorObject.cpp
void acceptorObject::setupConnections(QThread& thread, Simulation * simulation)
{
QObject::connect(&thread, SIGNAL(started()), this, SLOT(acceptNewClients()));
}
acceptNewClients() method works in infinite loop. At this point if I close my program I would get an error:
QThread destroyed while thread is still running
I looked through similar problems at stack and one guy said that I need to break the loop before finishing the thread in order to get rid of this bug. He also suggested to use a flag in infinite loop and emit a signal in destructor that will change the flag and eventually break the loop. It KINDA worked when I did something like this:
QObject::connect(&thread, SIGNAL(started()), this, SLOT(acceptNewClients()));
QObject::connect(this, SIGNAL(finishThread(bool)), this, SLOT(acceptNewClients(bool)));
And then emited finishThread(true) signal from destructor so I directly changed the flag. Of course I changed slot signature as well so it won't run in new thread anymore.
destructor code:
emit finishThread(true);
this->thread()->quit();
if(!this->thread()->wait(3000))
{
this->thread()->terminate();
this->thread()->wait();
}
How can I make this work?
What I've tried so far:
Adding a new slot that will change the flag. Result: when I close program the window dissapears but the proccess is still running. I think that destructor destroys the object before its emited signal is proccessed .
Making bool argument in acceptNewClients() slot a default one. Result: it overloads the funtion so one is run in different thread and the second one tries to change the flag which obviously doesn't work because they are completely different functions.
Solution:
connect(this, SIGNAL(finishThread()), &thread, SLOT(quit()));
connect(this, SIGNAL(finishThread()), this, SLOT(deleteLater()));
It was pointless to change slot function signature in this case.
In deconstructor I simply emit finishThread() signal, nothing more.
One way is instead of doing a while(true) in acceptNewClients you instead do
void acceptorObject::acceptNewClients(){
// do accept new client
QMetaObject::invokeMethod(this, "acceptNewClients", Qt::QueuedConnection);
}
In essence making the loop external.
The other option is to make everything use signals, QTcpServer (which I think you are using) has a newConnection signal you can connect to. Instead of using waitForNewConnection.

Pausing QThread's event dispatch loop

I have a multithreaded application written in C++ with Qt. Currently, my application works by having a QThread instance (I have NOT subclassed QThread) which uses the default run() implementation that just calls QThread's exec() method, which provides an event dispatch loop.
I call moveToThread on certain QObject subclasses which actually perform the work I want done in a separate thread. I tell these objects to do work using Qt's signals/slots mechanism. I stop the thread gracefully by informing my worker objects to stop their work, and then calling quit() and wait() on my thread. This all works very nicely.
However, I now want to implement the following scenario:
The user clicks e.g. the "X" button on my application, because they want to close it.
I don't want any new work to be started, so I pause the event dispatch thread. If the current event being dispatched continues running, that's fine.
I prompt the user, allowing them to either a) discard all remaining jobs and exit (using quit() andwait()` - this already works), or b) don't exit the application, but instead continue working (resume the thread).
My problem is that QThread doesn't seem to have a pause() method. I've seen various examples online which add one (like the answers to this question). The problem is that these examples depend on having a custom run() implementation, and implementing pause there. Since I'm relying on QThread's event dispatch loop, these solutions won't work. I've considered doing something like reimplementing exec() or creating my own subclass of QAbstractEventDispatcher, but these solutions seem like a whole lot of work to get simple pause / resume functionality.
What's the easiest way to pause QThread's event dispatch loop (preventing it from dispatching any new events, but letting the current event continue)?
I tried out the method suggested in the comments, but it took a bit of screwing around to get it to work totally correctly, so here's what I ended up with:
I subclassed QThread to add two new methods: pause and resume. There were a few things that needed to be dealt with delicately:
Calling start() while the thread is still running does nothing. Since resume() might be called before the thread's existing job stops running, we need to do the actual resume in a slot connected to the thread's finished() signal.
The finished() signal may be emitted just before the thread actually stops. Because of this, we need to call wait() in our slot before calling start().
If resume() is called after the thread is already stopped, simply setting state variables won't work, because finished() will never be emitted. Because of this, we need to deal with that case by having non-signal-related resume code in the resume() method as well.
Here's the final product.
pausablethread.h:
#ifndef INCLUDE_PAUSABLE_THREAD_H
#define INCLUDE_PAUSABLE_THREAD_H
#include <QThread>
class QMutex;
class PausableThread : public QThread
{
Q_OBJECT
public:
PausableThread(QObject *parent = 0);
virtual ~PausableThread();
void pause();
void resume();
private:
QMutex *controlMutex;
bool paused;
bool resumeScheduled;
private Q_SLOTS:
void doResume();
};
#endif
pausablethread.cpp:
#include "pausablethread.h"
#include <QMutex>
#include <QMutexLocker>
PausableThread::PausableThread(QObject *parent)
: QThread(parent), paused(false), resumeScheduled(false)
{
controlMutex = new QMutex(QMutex::NonRecursive);
QObject::connect(this, SIGNAL(finished()),
this, SLOT(doResume()));
}
PausableThread::~PausableThread()
{
delete controlMutex;
}
void PausableThread::pause()
{
QMutexLocker locker(controlMutex);
if(paused)
return;
paused = true;
quit();
}
void PausableThread::resume()
{
QMutexLocker locker(controlMutex);
if(!paused)
return;
if(resumeScheduled)
return;
if(isFinished())
{
start();
paused = false;
resumeScheduled = false;
}
else
{
resumeScheduled = true;
}
}
void PausableThread::doResume()
{ /* SLOT */
QMutexLocker locker(controlMutex);
if(!resumeScheduled)
return;
paused = false;
resumeScheduled = false;
wait();
start();
}
This seems to work, mostly. I believe there are some potential race conditions if the thread happens to finish or start at the same time execution is inside resume() or doResume() in a different thread. It's not exactly clear to me how to solve this.
I tried something like overriding the superclass's start() slot with the following:
void start(Priority priority)
{
QMutexLocker locker(controlMutex);
QThread::start(priority);
}
The problem with this is that start() never actually returns until the thread finishes, so it never releases its lock on the mutex. Thus, when doResume() tries to acquire a lock, a deadlock is encountered, and the thread isn't successfully resumed.
I think what is really needed is a mutex which is exclusively locked any time the thread's running state is changed, but it isn't clear to me how to implement this.
Regardless, the window for this race to occur is very small,and this works "well enough" to answer my question. Thanks to #Lol4t0 for the suggestion!

Qt Exiting Event Loop

I want to monitor an Emergency Stop button in custom equipment attached to a Beaglebone, my code is developed with Qt 4.6.
At the moment, I successfully 'show' a message box (without any buttons) when the Emergency Stop button is pressed. What I want to do is to proceed with the program ONLY when the Emergency Stop button is released. The Button press/release emit separate signals on each event. However, using this code the EmergencyStopIsInactive signal is never detected.
QEventLoop loop;
connect(this, SIGNAL(EmergencyStopIsInactive()), &loop, SLOT(quit()));
loop.exec(QEventLoop::AllEvents);
qDebug() << "Emergency Stop Deactivated";
In fact, using breakpoints I can see that it is never generated. The Eventloop seems to not receive the signal.
If I comment out the loop.exec line, using breakpoints I can see that the code emits the signal. With the exec command back in, we never reach the breakpoints.
The exec() does not seem to be allowing the application to process events.
Can I get this to work the way I want? How?
Regards,
James
=======================================
Edit:
This is the code that generates the initial signal:
// Set up Emergency Stop Input
EmStop = new mita_gpio;
EmStop->initgpio_read(49);
connect(EmStop,SIGNAL(StateOutput(unsigned int)), this, SLOT(update_EmStop(unsigned int) ) );
connect(EmStop,SIGNAL(StateOutput(unsigned int)), Test_Screen, SLOT(update_EmStop(unsigned int) ) );
connect(this,SIGNAL(EmergencyStopIsInactive()), Probe_Screen, SLOT(quit() ) );
connect(Probe_Screen,SIGNAL(ShowEmergencyStopScreen()),this,SLOT(EmergencyStopScreenShow()) );
This signal is then chained to the following:
void Manager::update_EmStop(unsigned int state_value)
{
if (state_value == 1)
{
MitaData.EmergencyStop = 1;
emit EmergencyStopIsActive();
qDebug() << "Emergency Stop = 1";
}
else
{
MitaData.EmergencyStop = 0;
emit EmergencyStopIsInactive();
qDebug() << "Emergency Stop = 0";
}
}
SIGNAL(EmergencyStopIsInactive()) is executing in the main event loop of your program (I logically assume).
When you start a new event loop, you run it with the blocking function exec and thus despite your new loop is running, you are blocking the main event loop.
loop.exec(QEventLoop::AllEvents);
Since your signal is supposed to be sent from the main loop, that is blocked by your blocking function loop.exec, it will never be sent until the loop.exec is returning.
To solve that issue, whether generate the EmergencyStopIsInactive() signal from within the "loop" event loop, or put this second loop inside a separate thread.

Multi-threading in Qt problematic?

I have been learning Qt for a while and a few days ago I decided to go on multi-threading by QThread. I have been following this person. Since he says that subclassing QThread is not the appropriate way but by using QObject is. I am following his method. But he has created another class which inherits from QObject. I decided to make a few changes:
class myclass
{
private:
dowork();
private slots:
slota();
slotb();
slotc();
}
myclass::dowork()
{
QThread lett;
QThread latt;
QThread pltt;
QObject lethread;
connect(&lett, SIGNAL(started()), this, SLOT(slota()));
lethread.moveToThread(&lett);
QObject lathread;
connect(&latt, SIGNAL(started()), this, SLOT(slotb()));
lathread.moveToThread(&latt);
QObject plthread;
connect(&pltt, SIGNAL(started()), this, SLOT(slotc()));
plthread.moveToThread(&pltt);
lett.start();
latt.start();
pltt.start();/*
lett.wait();
latt.wait();
pltt.wait();*/
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
}
If I run the program it keeps running while loop infinitely! It doesn't come out of that at all.
I used qdebug inside the implementation of the 3 slots to check whether it is entering them or not, and surprisingly none of the slots gets called. Why is that so?
If I remove the comments for .wait then the program pauses.
What is wrong in this method? I want to avoid that extra class as my program is very small.
while(lett.isRunning())
{
//qDebug() << "Still Running!";
}
lett.quit();
Terribly wrong. The current thread is busy waiting and will be eating all the time. But this is not your problem. Your problem is certainly that the main event loop has probably not started yet, ie you didn't do QApplication.exec() yet.
Qt uses events to start threads, and when you do use movetoThread, start, specific events are queued in the current thread (ie the thread executing these methods). If the main event loop has already started, then will be processed as soon as they can. But in your case I bet that you main function is :
int main(){
QApplication app();
myclass onlyclassIwanttomake;
onlyclassIwanttomake.dowork();
app.exec(); <----HERE!!!
}
The thread will be started when the main thread executes app.exec();. When you are busy waiting, you are preventing the main thread to process the events required to start your
events.
EDIT: Well, another issue is that
lett.start();
latt.start();
pltt.start();
start 3 threads which are started, and stay idle forever. They are not doing anything, but they are running (even if you remove your loop).
This is a entry written about Qt threading. Please take the time to read it.

Terminating thread

I've a dialog displaying progress bar + some other data, and I also have a cancel button on this dialog. While this dialog is displayed there is potentially heavy computation going on, which is show on progress bar. This computation is started from withing this dialog code so I have:
Counting_Progress_Dialog::Counting_Progress_Dialog(QWidget *parent) :
QDialog(parent)
{
setupUi(this);
thread_ = new Threaded;//THIS IS THE THREAD IN WHICH COMPUTATION IS BEING PERFORMED
connect(thread_,SIGNAL(counter_value(int)),this,SLOT(update_progress_bar(int)));
connect(this,SIGNAL(rejected()),thread_,SLOT(terminate()),Qt::QueuedConnection);//
HERE I'M CONNECTING REJECTED ON DIALOG TO TERMINATE ON THREAD
}
void Counting_Progress_Dialog::start()
{
thread_->start(QThread::LowestPriority);
}
and I do invoke this in part of the program:
void My_Class::dummy_()
{
auto old_priority = this->thread()->priority();
this->thread()->setPriority(QThread::HighestPriority);
Counting_Progress_Dialog progress;
progress.start();//this will start thread
progress.exec();//this will enter it's event loop
progress.wait();//this will wait until thread is finished
this->thread()->setPriority(QThread::NormalPriority);
}
But despite all this, when I press cancel on my dialog, the whole application freezes. What am I doing wrong? How to make it behave correctly?
UPDATED:
void Counting_Progress_Dialog::wait()
{
thread_->wait();
}
I see that you are connecting using 2 different strategies. But if thread_ and this(counting dialog) are really within two separated threads then the connection will always be Qt::QueuedConnection. Well that's not the issue.
progress.exec();//this will enter it's event loop
Calling exec() suspend the execution of dummy_() until the dialog have to return. And when the dialog return your thread is terminated. So I don't see the purpose of
progress.wait();//this will wait until thread is finished
By the way which function is that? the only one I know is Qthread::wait(). I am pretty confident the issue is here...
edit:
progress.wait() is not the issue... But it is possible that the events sent by the thread are causing trouble in some way. Use the debugger or some qDebug() to see if update_progress_bar is called after you push cancel.