Clean up QThread after calling quit() - qt

I have a problem. If I call Abort(), run function will return without complexMath instance have enough time to do clean up.
What i want is, after calling Abort(), complexMath instance have enough time to shutdown itself, clearing all pending signal and slot(inside complexMath, it also have it own signal and slots) before it return.
void MyThread::Go(){
start();
}
void MyThread::Abort(){
emit stopNow();
quit();
}
void MyThread::run(){
ComplexMath * complexMath = new ComplexMath();
connect( complexMath, SIGNAL(OnCalculation(qint)), this, SLOTS(PartialOutput(qint)) );
connect( this, SIGNAL(stopNow()), complexMath, SLOTS(deleteLater());
exec();
}
void MyThread::PartialOutput(qint data){
qDebug() << data;
}
Thanks!

I think you can get rid of the stopNow signal:
void MyThread::Abort(){
quit();
}
void MyThread::run(){
ComplexMath * complexMath = new ComplexMath();
connect( complexMath, SIGNAL(OnCalculation(qint)), this, SLOTS(PartialOutput(qint)) );
exec();
// Any code here will be run after the thread quits, and the event loop stops
deleteLater();
}

Related

Exit QThread when GUI Application exits

I have the following worker class:
class MediaWorker : public QObject
{
Q_OBJECT
public:
explicit MediaWorker(QObject *parent = 0);
~MediaWorker();
void Exit();
signals:
void Finished();
public slots:
void OnExecuteProcess();
};
In MediaWorker.cpp
void MediaWorker::Exit()
{
emit Finished();
}
void MediaWorker::OnExecuteProcess()
{
qDebug() << "Worker Thread: " << QThread::currentThreadId();
}
In my MainWindow I do the following:
this->threadMediaWorker = new QThread();
this->mediaWorker = new MediaWorker();
this->timerMediaWorker = new QTimer();
this->timerMediaWorker->setInterval(1000);
this->timerMediaWorker->moveToThread(this->threadMediaWorker);
this->mediaWorker->moveToThread(this->threadMediaWorker);
connect(this->threadMediaWorker, SIGNAL(started()), this->timerMediaWorker, SLOT(start()));
connect(this->timerMediaWorker, &QTimer::timeout, this->mediaWorker, &MediaWorker::OnExecuteProcess);
connect(this->mediaWorker, &MediaWorker::Finished, this->threadMediaWorker, &QThread::quit);
connect(this->mediaWorker, &MediaWorker::Finished, this->mediaWorker, &MediaWorker::deleteLater);
connect(this->threadMediaWorker, &QThread::finished, this->mediaWorker, &QThread::deleteLater);
this->threadMediaWorker->start();
The threading is working properly. When I close the application I terminate the thread in the destructor:
MainWindow::~MainWindow()
{
delete ui;
this->mediaWorker->Exit();
}
so Exit() emits the Finished signal which will hopefully delete the qthread and mediaworker class.
My question is if this is the proper way of terminating both the thread and media worker class?
My question is what is the proper way of terminating both the
worker thread and media worker class?
You can just ensure that the 'media' object gets deleted while the main window gets destructed by using either QScopedPointer or std::unique_ptr.
class MainWindow : public QMainWindow {
/// ...
QThread m_workerThread;
QScopedPointer<MediaWorker> m_pMediaObject;
/// ...
};
void MainWindows::init()
{
// ... other initialization skipped ...
// for dynamic allocation of the object and keeping the track of it
m_mediaObject.reset(new MediaWorker());
m_workerThread.moveToThread(m_mediaObject.data());
}
void MainWindow::stopWorker()
{
if (m_workerThread.isRunning())
{
m_workerThread.quit(); // commands Qt thread to quit its loop
// wait till the thread actually quits
m_workerThread.wait(); // possible to specify milliseconds but
// whether or not to limit the wait is
// another question
}
}
If the worker thread used for updating the UI it makes sense to attempt to stop the worker thread before the UI objects released in
void MainWindow::closeEvent(QCloseEvent *)
{
stopWorker();
}
But there is a chance that the main window never gets closeEvent() called before the destruction so we should handle that:
MainWindow::~MainWindow()
{
stopWorker();
// it also destroys m_mediaObject
}

How can I avoid infinite loop when modifying textboxes (QLineEdit) that change related item info?

I have several fields in a widget, that each can affect the behavior of an item, and changing some of them will change others.
I read somewhere that the editingFinished() signal of a line edit is triggered only by user actions - and not by code changes... Is that true ?
connect(m_lineEdit1, SIGNAL(editingFinished()), this, SLOT(m_lineEdit1Changed()));
connect(m_lineEdit2, SIGNAL(editingFinished()), this, SLOT(m_lineEdit2Changed()));
connect(this, SIGNAL(someSignal()), this, SLOT(updateData()));
void m_lineEdit1Changed()
{
changedata1();
emit someSignal();
}
void m_lineEdit2Changed()
{
changedata2();
emit someSignal();
}
void updateData()
{
m_lineEdit1.setText(fromdata);
m_lineEdit2.setText(fromdata);
}
If I change m_lineEdit1, and update the entire widget (which changes, through code, m_lineEdit2), I hit a breakpoint in m_lineEdit2Changed()
This leads to an infinite loop of updates...
What can I do to get around it ?
Blocking signals is a bit of a sledgehammer of an approach. You can use a sentinel class to explicitly prevent recursion:
#define SENTINEL_STRINGIFY(x) #x
#define SENTINEL_TOSTRING(x) SENTINEL_STRINGIFY(x)
#define SENTINEL_AT __FILE__ ":" SENTINEL_TOSTRING(__LINE__)
class Sentinel {
Q_DISABLE_COPY(Sentinel);
static QMutex m_mutex;
static QSet<QString> m_sentinels;
QString const m_sentinel;
bool const m_ok;
static bool checkAndSet(const QString & sentinel) {
QMutexLocker lock(&m_mutex);
if (m_sentinels.contains(sentinel)) return false;
m_sentinels.insert(sentinel);
return true;
}
public:
explicit Sentinel(const char * sentinel) :
m_sentinel(sentinel), m_ok(checkAndSet(m_sentinel)) {}
~Sentinel() {
if (!m_ok) return;
QMutexLocker lock(&m_mutex);
m_sentinels.remove(m_sentinel);
}
bool operator()() const { return m_ok; }
};
QMutex Sentinel::m_mutex;
QSet<QString> Sentinel::m_sentinels;
...
void Foo::m_lineEdit1Changed()
{
Sentinel s(SENTINEL_AT);
if (!s) return; // exit if this method is on the call stack
...
changedata1();
emit someSignal();
}
This is thread-safe and can be used from any thread.
A technique to avoid this problem is to use the QObject::blockSignals() function.
In your example you would do:
void updateData()
{
m_lineEdit1.blockSignals(true);
m_lineEdit1.setText(fromdata);
m_lineEdit1.setText(fromdata);
m_lineEdit1.blockSignals(false);
}
The blockSignals() call prevents the object sending any signals while you are changing the data in the line edit.

QMYSQLResult::cleanup: unable to free statement handle

I'm trying to use a thread to bring data from a MySQL database, but after a call to:
QThread* thread = new QThread;
Beacon *beacon = new Beacon(m_db, begin, end);
beacon->moveToThread(thread);
connect(beacon, &Beacon::values, this, &Tm::insertRow);
connect(beacon, &Beacon::finished, thread, &QThread::quit);
connect(beacon, &Beacon::finished, beacon, &Beacon::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
connect(thread, &QThread::started, beacon, &Beacon::executeQuerySmooth);
connect(beacon, &Beacon::finished, this, &Tm::finished);
thread->start();
I get:
QMYSQLResult::cleanup: unable to free statement handle
And the next time a try to use the connection I get:
QSqlError("2006", "QMYSQL: Unable to execute query", "MySQL server has gone away")
What might be happening?
You can only use the connection from a thread that created it (reference), or in general from one thread only.
There are two approaches you can take:
Maintain the database connection in a dedicated thread, and use it from there. The use of shortlived threads is a premature pessimization anyway, so it was a bad approach to begin with.
Move the database connection between worker threads from a thread pool. Use QtConcurrent::run to run a functor on a thread from the thread pool.
Note: Beacon::Beacon(...) constructor can't be using the database, it can only store a reference/pointer to it!
See this answer for more about postCall.
template <typename T>
void postCall(QThread * thread, T && functor) {
QObject source;
QObject::connect(&source, &QObject::destroyed,
QEventDispatcher::instance(thread), std::forward(functor));
}
Workers From The Thread Pool
class Tm : public QObject {
Q_OBJECT
QMutex m_dbMutex;
QSqlDatabase m_db;
Q_SIGNAL void openFailed();
Q_SIGNAL void openSucceeded();
public:
void openConnection() {
QMutexLocker lock(&m_dbMutex);
m_db.addDatabase("QSQLITE");
... // set database's properties
m_db.moveToThread(0); // we don't know what thread it will be used in
lock.unlock();
QtConcurrent::run([this]{
QMutexLocker lock(&m_dbMutex);
m_db.moveToThread(QThread::currentThread());
bool rc = m_db.open();
if (rc) {
m_db.moveToThread(0);
emit openSucceeded();
} else {
m_db.moveToThread(this->thread());
emit openFailed();
}
});
}
void beaconate() {
...
QSharedPointer<Beacon> beacon(new Beacon(&m_db, begin, end));
connect(beacon, &Beacon::values, this, &Tm::insertRow);
connect(beacon, &Beacon::finished, this, &Tm::finished);
beacon->setMoveToThread(0);
QtConcurrent::run([beacon]{
beacon->moveToThread(QThread::currentThread());
QMutexLocker lock(&m_dbMutex);
m_db.moveToThread(QThread::currentThread());
QEventLoop loop; // only if Beacon needs one
connect(beacon, &Beacon::finished, &loop, &QEventLoop::quit);
beacon->executeQuerySmooth();
loop.exec();
m_db.moveToThread(0);
});
}
~Tm() {
QMutexLocker lock(&m_dbMutex);
m_db.moveToThread(thread());
}
...
};
Dedicated Thread
class Thread : public QThread
{ using QThread::run; public: ~Thread() { quit(); wait(); } };
class Tm : public QObject {
Q_OBJECT
QSqlDatabase m_db;
Thread m_dbThread; // must be declared after m_db, so that it's destructed prior to m_db
Q_SIGNAL void openFailed();
Q_SIGNAL void openSucceeded();
public:
Tm(QObject * parent = 0) : QObject(parent) {
m_dbThread.start();
}
void openConnection() {
m_db.addDatabase("QSQLITE");
... // set database's properties
m_db.moveToThread(&m_dbThread);
postCall(&m_dbThread, [this]{
if (! m_db.open()) {
m_db.moveToThread(this->thread());
emit openFailed();
} else
emit openSucceeded();
});
}
void beaconate() {
...
auto beacon = new Beacon(&m_db, begin, end);
beacon.moveToThread(&m_dbThread);
connect(beacon, &Beacon::values, this, &Tm::insertRow);
connect(beacon, &Beacon::finished, beacon, &Beacon::deleteLater);
connect(beacon, &Beacon::finished, this, &Tm::finished);
postCall(&m_dbThread, [beacon]{ beacon->executeQuerySmooth(); });
}
~Tm() {
// Destructing objects living in other threads is undefined behavior
postCall(&m_dbThread, [this]{
if (m_db.thread() == QThread::currentThread())
m_db.moveToThread(thread());
});
}
...
};

Qt widget element doesn't want to hide

In my Qt application after pressing button I want to hide that button and start quite long process. While this process is running PushButton shouldn't be visible but it seems to be waiting for process being executed and after that hide button. It looks like QWidget is refreshing after end of PushButton slot function. Here's my simplified code:
void MainWindow::on_pushButton_clicked()
{
ui->progressBar->setVisible(true);
ui->pushButton->setVisible(false);
while(x<1000000) x++; //e.g of my long time function
}
When that function (on_pushButton_clicked() -> generated by mouse->go to slot) ends up my "view" is updated and button dissappear.
Is there any function to refresh my widget or maybe I forgot about sth?
Thanks in advance
Changes to the gui aren't shown until the program has a chance to redraw itself which won't happen until you return.
you'll need to defer the execution of the code somehow:
void MainWindow::on_pushButton_clicked()
{
ui->progressBar->setVisible(true);
ui->pushButton->setVisible(false);
QMetaObject::invokeMethod(this, &MainWindow::longFunction, Qt::QueuedConnection);
}
void MainWindow::longFunction()
{
while(x<1000000) x++; //e.g of my long time function
}
This returns to the event loop and then runs the longFunction but it will still block on and the progress bar won't show any updates until it is done.
To fix that you will either need to move the execution to a new thread or split the function up in shorter parts and invoke them in sequence with QMetaObject::invokeMethod and a QueuedConnection.
In order for the button to change state, it needs to return to process events in the event loop.
You could call QApplication::processEvents before the while loop in order to fix this, though it would be better to return to the event loop naturally, before you start the long-time function, by invoking the function as a QueuedConnection.
Alternatively, the better method would be to run the function in a separate thread, which will enable your GUI to remain active during the processing of the 'long function'
Start by creating an object to encapsulate the function that will do the work:-
class Worker : public QObject {
Q_OBJECT
public:
Worker();
~Worker();
public slots:
void process(); // This is where your long function will process
signals:
void finished();
void error(QString err);
};
void Worker::process()
{
while(x<1000000) x++; //e.g of my long time function
emit finished();
}
Create a new thread and start it when the button is clicked
void MainWindow::on_pushButton_clicked()
{
// change button visibility
ui->progressBar->setVisible(true);
ui->pushButton->setVisible(false);
// create the new thread and start the long function
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
//ensure the objects are cleared up when the work is done
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
//start the thread and the long function processing
thread->start();
}

QTimer in a thread - events not processing?

I have an object that is derived from QThread and the class definition includes the Q_OBJECT macro. I created a timer within the thread so I can do some occasional checks while the thread is running; however, the timeout event is never occurring.
I've tried making the timer a singleshot as well, but no events are emitted.
Are events processed in a thread by default or do I need to do something else to have them processed?
Here's the code for how I set up the thread and timers:
void MyClass::run( void )
{
checkTimer_chA = new QTimer( this );
qDebug() << connect( checkTimer_chA, SIGNAL( timeout() ), this, SLOT( timerExpiry_chA() ) );
checkTimer_chA->start( 1000 );
// prevent multiple, simultaneous starts
if( !isRunning )
{
qDebug() << "Thread: MyClass::run";
isRunning = true;
while( isRunning )
{
getData();
processData();
yieldCurrentThread();
}
}
checkTimer_chA->stop();
delete checkTimer_chA;
}
void DAQ::timerExpiry_chA( void )
{
qDebug() << "timerExpiry_chA";
checkTimer_chA->stop();
}
If I add QApplication::processEvents(); right before the call to yieldCurrentThread(); the timer works as expected. However, this seems wrong to me.
Working with threads in Qt can sometimes be a bit of a hassle. This blog post was a real eye opener for me. In case we adopt the style proposed in the blog post to your problem we end up with a solution like below.
Consumer::Consumer():
checkTimer_(new QTimer(this))
{
QObject::connect(checkTimer_, SIGNAL(timeout()), this, SLOT(onTimerExpiration());
QObject::connect(this, SIGNAL(ready()), this, SLOT(consume());
}
bool Consumer::event(QEvent *e)
{
if (e->type() == QEvent::ThreadChange)
{
QTimer::singleShot(0, this, SLOT(start());
}
return QObject::event(e);
}
void Consumer::consume()
{
getData();
processData();
emit ready();
}
void Consumer::start()
{
checkTimer_->start(1000);
emit ready();
}
void Consumer::onTimerExpiration()
{
qDebug() << "timeout";
}
Then run it in a separate thread as follows:
...
Consumer *consumer = new Consumer();
...
QThread *thread = new QThread(this);
thread->start();
consumer->moveToThread(thread);
All child objects of Consumer will run in the context of the thread Consumer was moved to. It is possible to create a timeout signal for the Consumer class and connect it with an object that is not running in thread. Qt will ensure that the proper signal/slot types are applied to the connection once the object is moved to the thread.
I left out the whole isRunning part as I doubt you will still need it as long as you only create one Consumer.
Threads do not have their own event loops unless you explicitly create event loops in them. See http://doc.qt.io/qt-5/threads-qobject.html#per-thread-event-loop for details.
Perhaps you need an event loop running on the thread. What about changing the code to the following?
void MyClass::run( void )
{
checkTimer_chA = new QTimer( this );
qDebug() << connect( checkTimer_chA, SIGNAL( timeout() ), this, SLOT( timerExpiry_chA() ) );
checkTimer_chA->start( 1000 );
// prevent multiple, simultaneous starts
if( !isRunning )
{
qDebug() << "Thread: MyClass::run";
isRunning = true;
QTimer::singleShot(0, this, SLOT(process()));
exec();
}
checkTimer_chA->stop();
delete checkTimer_chA;
}
void MyClass::process()
{
if( isRunning )
{
getData();
processData();
yieldCurrentThread();
QTimer::singleShot(0, this, SLOT(process()));
}
else
QThread::exit();
}
void MyClass::timerExpiry_chA( void )
{
qDebug() << "timerExpiry_chA";
checkTimer_chA->stop();
}

Resources