I am creating an example to understand threads in Qt and want my worker thread to sleep for 1 second between each increment so I can see the debug output. But the sleep makes my main GUI thread non-responsive.
Here is my slot functoin in OddCounter class.
void OddCounter::count()
{
for (int i = 0; i < 10; i++)
{
counter += 2;
qDebug() << counter;
QThread::sleep( 1 );
}
}
My mainwindow class which calls this thread is:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
oddCounter = new OddCounter;
connect(this, SIGNAL(startOddCounter()), evenCounter, SLOT(count()), Qt::QueuedConnection );
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
OddCounter oddCounter;
oddCounter.moveToThread( &thread );
thread.start();
emit startOddCounter();
}
The problem is when I press the button, the counter works and displays the next increment after each second passed but the mainwindow is non responsive all this time! This is not right! I want my mainwindow to be responsive and only the thread should sleep. How do I do that?
You have an error in your code: you are creating another OddCounter which you move to the different thread but your original oddCounter to which the signal is connected still lives in the main thread. You should change your code to this:
void MainWindow::on_pushButton_clicked()
{
oddCounter->moveToThread( &thread );
thread.start();
emit startOddCounter();
}
Related
I have a bigger project, with a GUI and I want to manage some files in the background. I've implemented a new thread for this task and on runtime, everything works great. But as soon as I quit the application visual-leak-detector finds 3-7 memory leaks.
I separated my threading code and created a new project to check this with a minimal code example, but I'm still not able to fix my issue.
I think it has something to do with the event loop of the main program. Maybe the loop doesn't process the last events to delete my thread class and the thread itself. Because I stop and quit the thread in a destructor. But I'm not sure on this one.
Here is my minimal code:
threadclass.hpp:
#include <QObject>
#include <QDebug>
class ThreadClass : public QObject {
Q_OBJECT
public:
explicit ThreadClass() {}
virtual ~ThreadClass(){
qDebug() << "ThreadClass Destructor";
}
signals:
// emit finished for event loop
void finished();
public slots:
// scan and index all files in lib folder
void scanAll(){
for(long i = 0; i < 10000; i++){
for (long k = 0; k < 1000000; k++);
if(i%500 == 0)
qDebug() << "thread: " << i;
}
}
// finish event loop and terminate
void stop(){
// will be processed after scanall is finished
qDebug() << "STOP SIGNAL --> EMIT FINSIHED";
emit finished();
}
};
threadhandler.hpp:
#include <QObject>
#include <QThread>
#include "threadclass.hpp"
class ThreadHandler : public QObject {
Q_OBJECT
public:
explicit ThreadHandler(QObject *parent = 0) : parent(parent), my_thread(Q_NULLPTR) {}
virtual ~ThreadHandler() {
// TODO Check!
// I think I don't have to delete the threads, because delete later
// on finish signal. Maybe I just have to wait, but then how do I
// check, if thread is not finished? Do I need to make a bool var again?
if (my_thread != Q_NULLPTR && my_thread->isRunning())
{
emit stopThread();
//my_thread->quit();
my_thread->wait();
//delete my_thread;
}
qDebug() << "ThreadHandler Destructor";
my_thread->dumpObjectInfo();
}
void startThread(){
if (my_thread == Q_NULLPTR)
{
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);
QObject::connect(this, &ThreadHandler::stopThread, 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();
}
}
signals:
void stopThread();
private:
QObject *parent;
QThread* my_thread;
};
The main.cpp is crappy but seems to simulate the behavior of my main program well enough:
#include <QCoreApplication>
#include <QTime>
#include <QDebug>
#include "threadhandler.hpp"
#include <vld.h>
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
ThreadHandler *th = new ThreadHandler();
th->startThread();
// wait (main gui programm)
QTime dieTime= QTime::currentTime().addSecs(5);
while (QTime::currentTime() < dieTime) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
qDebug() << "DELETE TH";
delete th;
qDebug() << "FINISH ALL EVENTS";
QCoreApplication::processEvents(QEventLoop::AllEvents, 500);
qDebug() << "QUIT";
QCoreApplication::quit();
qDebug() << "CLOSE APP";
// pause console
getchar();
// return a.exec();
}
Here is the output from VLD:
WARNING: Visual Leak Detector detected memory leaks!
...
turns out this is very boring and uninteresting
...
Visual Leak Detector detected 3 memory leaks (228 bytes).
Largest number used: 608 bytes.
Total allocations: 608 bytes.
Visual Leak Detector is now exiting.
The program '[8708] SOMinimalExampleThreads.exe' has exited with code 0 (0x0).
Update 1: I added qDebug() << "ThreadClass Destructor"; to the destructor of the ThreadClass and my new output looks like this:
...
thread: 9996
thread: 9997
thread: 9998
thread: 9999
ThreadHandler Destructor
FINISH ALL EVENTS
CLOSE APP
Now it is clear that the destructor of my threaded class is never called and therefore lost in the void. But then why is this not working?
QObject::connect(my_threaded_class, &ThreadClass::finished, my_threaded_class, &ThreadClass::deleteLater);
Update 2: I found one problem in ThreadHandler:
emit stopThread();
my_thread->quit(); // <-- stops the event loop and therefore no deletelater
my_thread->wait();
I removed my_thread->quit() and now the destructor of ThreadClass is called, but my_thread->wait() never finishes.
Problem description:
When the destructor of ThreadHandler emits stopThread from the main thread, Qt invokes the connected slot (&ThreadClass::stop) by posting an event into the worker thread's event loop (aka, a queued connection). This means that the event loop of the worker's needs to be ready for receiving new events when this signal is emitted (since you are relying on it to perform proper clean-up). However, as you've already spotted, the call to thread->quit() might cause the event loop to quit earlier than desired (before the worker thread makes its way to call ThreadClass::stop, and hence the signal ThreadClass::finished is not emitted). You might want to examine the output of this minimal example that reproduces the behavior I am talking about:
#include <QtCore>
/// lives in a background thread, has a slot that receives an integer on which
/// some work needs to be done
struct WorkerObject : QObject {
Q_OBJECT
public:
using QObject::QObject;
Q_SLOT void doWork(int x) {
// heavy work in background thread
QThread::msleep(100);
qDebug() << "working with " << x << " ...";
}
};
/// lives in the main thread, has a signal that should be connected to the
/// worker's doWork slot; to offload some work to the background thread
struct ControllerObject : QObject {
Q_OBJECT
public:
using QObject::QObject;
Q_SIGNAL void sendWork(int x);
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread thread;
WorkerObject workerObj;
workerObj.moveToThread(&thread);
// quit application when worker thread finishes
QObject::connect(&thread, &QThread::finished, &a, &QCoreApplication::quit);
thread.start();
ControllerObject controllerObj;
QObject::connect(&controllerObj, &ControllerObject::sendWork, &workerObj,
&WorkerObject::doWork);
for (int i = 0; i < 100; i++) {
QThread::msleep(1);
// call thread.quit() when i is equal to 10
if (i == 10) {
thread.quit();
}
controllerObj.sendWork(i);
}
return a.exec();
}
#include "main.moc"
On my machine, Here is a possible output:
working with 0 ...
working with 1 ...
working with 2 ...
working with 3 ...
Notice that, despite the fact that thread.quit() is called on the tenth iteration from the main thread, the worker thread might not process all messages received before the exit call (and we get the value 3 as the last value processed by the worker).*
Solution:
Actually, Qt provides a canonical to way to quit a worker thread and perform necessary clean-up, since the signal QThread::finished is handled in a special way:
When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(), to free objects in that thread.
This means that you can use thread->quit() (the same way you were doing), but you just need to add:
connect(my_thread, &QThread::finished, my_threaded_class, &ThreadClass::stop);
to your startThread and remove the unnecessary emit stopThread(); from the destructor.
* I couldn't find any page in the documentation that explains this behavior in detail, so I provided this minimal example to explain what I am talking about.
I found out that the my_thread->wait() function, blocks the event loop and therefore the quit and deleteLater cascade is never finished. I fixed this with another method of waiting for the finished thread:
removed
Here is the newly implemented solution from Mike. It was pretty easy to implement, I only had to change the connection to my_threaded_class::stop in the threadhandler class.
#include <QObject>
#include <QThread>
#include "threadclass.hpp"
class ThreadHandler : public QObject {
Q_OBJECT
public:
explicit ThreadHandler(QObject *parent = 0) : parent(parent), my_thread(Q_NULLPTR) {}
virtual ~ThreadHandler() {
if (my_thread != Q_NULLPTR && my_thread->isRunning())
{
my_thread->quit();
my_thread->wait();
}
qDebug() << "ThreadHandler Destructor";
}
void startThread(){
if (my_thread == Q_NULLPTR)
{
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();
}
}
signals:
void stopThread();
private:
QObject *parent;
QThread* my_thread;
};
I want to update a modal QProgressDialog from my worker thread. However, if I set the dialog to be modal, my application crashes (and the dialog did not show any progress). If I do not, everything goes fine (but the user can tinker around with the rest of the program, which may cause issues).
What am I doing wrong?
Minimum code sample follows:
filereader qfr;
QProgressDialog progress("Importing file.", "Cancel", 0, file_size);
connect(&qfr, &filereader::signalProgress, &progress, &QProgressDialog::setValue, Qt::QueuedConnection);
QThread worker_thread;
std::atomic<bool> success = false;
connect(&worker_thread, &QThread::started,
[&]() {
success = qfr.read_file(/* parameters */);
worker_thread.quit();});
worker_thread.start();
//progress.setWindowModality(Qt::WindowModal); // Works only fine when this line is commented !!
while (worker_thread.isRunning()) {
QApplication::processEvents();
QThread::sleep(0);
}
progress.close();
Your thread is pretty much pointless. It serves no real purpose. You could have as well just called QApplication::processEvents in your read_file method. But you shouldn't, calling processEvents is bad practice.
What you should do is remove that while loop, and make your progress dialog a member of your class. I don't really like how that lambda looks either. I would personally just use filereader::read_file as a slot.
Note that Qt::windowModal blocks input to the parent window. Your progress dialog has no parent. So you would either have to call progress->setModal(true), or progress.setWindowModality(Qt::ApplicationModal);. Or set a parent to it.
Here is a small example (it is not tailor made for your application, but it should point you in the right direction):
#include <QtWidgets>
class Worker : public QObject
{
Q_OBJECT
public:
Worker(QObject *parent = nullptr) : QObject(parent){}
public slots:
void simulateLongProcess()
{
for(int i = 0; i < 101; i++)
{
emit progressChanged(i);
QThread::msleep(100);
}
emit finishedWorking(true);
}
signals:
void progressChanged(int progress);
void finishedWorking(bool result);
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr) : QWidget(parent)
{
setLayout(new QHBoxLayout);
progress_dialog.setModal(true);
progress_dialog.setAutoReset(false);
progress_dialog.setCancelButton(nullptr);
QThread *thread = new QThread(this);
connect(thread, &QThread::started, &worker, &Worker::simulateLongProcess);
connect(&worker, &Worker::finishedWorking, thread, &QThread::quit);
connect(&worker, &Worker::progressChanged, &progress_dialog, &QProgressDialog::setValue);
connect(&worker, &Worker::finishedWorking, &progress_dialog, &QProgressDialog::close);
connect(&worker, &Worker::finishedWorking, this, &Widget::handleResult);
QPushButton * start_button = new QPushButton("START");
connect(start_button, &QPushButton::clicked, this, [=]
{
progress_dialog.show();
thread->start();
});
layout()->addWidget(start_button);
resize(400, 300);
}
public slots:
void handleResult(bool result)
{
// do something with the result
}
private:
QProgressDialog progress_dialog;
Worker worker;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
#include "main.moc"
I have my main thread which is in charge with the GUI and my worker thread which is in charge with doing stuff with my webcam.
I am able to emit a signal from my main thread to my webcam thread, but it never receives it! Could somebody explain me why?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setThreadsAndObj();
setConnects();
startCamera();
}
void MainWindow::setThreadsAndObj()
{
cameraClassPtr = new cameraClass();
cameraThread = new QThread();
}
void MainWindow::setConnects()
{
....
connect(this, &MainWindow::savePicture, cameraClassPtr, &cameraClass::takePicture);
}
void MainWindow::startCamera()
{
//camera start
connect( cameraThread, &QThread::started, cameraClassPtr, &cameraClass::getVideoFrame );
connect( cameraThread, &QThread::finished, cameraClassPtr, &QThread::deleteLater );
connect( cameraThread, &QThread::finished, cameraThread, &QThread::deleteLater );
//receive camera frames
connect(cameraClassPtr, &cameraClass::videoFrameToGui, this, &MainWindow::updateCameraStream);
//start threads
cameraClassPtr->moveToThread(cameraThread);
cameraThread->start();
}
void MainWindow::foo()
{
emit savePicture();
}
void cameraClass::takePicture()
{
qDebug()<<"camera class received signal"; //THIS NEVER GETS PRINTED
}
Could someone explain me why my signal is never received and "camera class received signal" is never printed and how to solve this?
I had this loop in my worker thread:
...
static cv::VideoCapture cap(-1);
if( !cap.isOpened() )
{
qDebug()<< "Could not initialize capturing...\n";
}
qDebug()<<"starting live camera";
cap.set(CV_CAP_PROP_FRAME_WIDTH,240);
cap.set(CV_CAP_PROP_FRAME_HEIGHT,320);
while(1)
{
cap >> imgFrame;
int fd = open("/home/John/Desktop/mainImglock.txt", O_RDWR |O_CREAT, 0666);
int rc = flock(fd, LOCK_EX | LOCK_NB);
if(rc==0)
{
cv::imwrite("/home/John/Desktop/camera.jpg", imgFrame);
}
flock(fd, LOCK_UN);
close(fd);
}
I solved the issue by adding: QApplication::processEvents(); in the while(1) loop, so that the event loop isn't hanging.
You need to subclass QThread and call QThread::exec(); in order to process events in this thread.
In the Worker Class I have two functions who works and control the thread, start() and abort()
void Worker::requestWork()
{
mutex.lock();
_working = true;
_abort = false;
qDebug()<<"Le thread travail de"<<this->myId<<" "<<thread()->currentThreadId();
mutex.unlock();
emit workRequested();
}
void Worker::abort()
{
mutex.lock();
if(_working) {
_abort = true;
qDebug()<<"Le thread "<<thread()->currentThreadId()<<" s'arrete";
}
mutex.unlock();
}
As you can see the workrequest emit a signal saying to the thread to start to work. And because the Worker Class is in the thread, how can I pause or restore it? From the worker class? from the MainWindow?
and now the Whole code.Mainwindow Class.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QObject::connect(ui->lineEdit,SIGNAL(textChanged(QString)),this,SLOT(command(QString)));
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(valueChanged(QString)), ui->label, SLOT(setText(QString)));
connect(worker, SIGNAL(workRequested()), thread, SLOT(start()));
connect(thread, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()), Qt::DirectConnection);
}
//QLineEdit send signal to slot "command" permit to control the thread
void MainWindow::command(QString text){
qDebug()<<"le message a bien ete intercepte";
qDebug()<<ui->lineEdit->text();
if (text.contains("help"))
qDebug()<<"heeeelp";
if (text.contains("pause")){
worker->Paused();
if(thread->isRunning()){}
//cond.wait()
}
if (text.contains("restart")){
worker->Restarted();
if (!thread->isRunning()){}
//cond.wakeAll();
}
if (text.contains("stopped")){
worker->Paused();
thread->wait();
}
if (text.contains("start")){
worker->requestWork();
}
if (text.contains("destroyed")){
worker->destroyed();
}
}
So my question is: how to pause and restart the thread from the command() slot when the User insert "Pause" ?
I think you mess up the two possible ways of doing work with QThread:
One is to have an object (Worker) moved to a start()ed QThread. This way you do work by calling slots on the Worker, the work is done when the slots execute. You don't pause/resume this - when the slot is done, QThread will wait for new work, the same way QApplication waits for events when it's idle.
Second way is subclassing QThread, reimplementing run() and creating (some sort of) Worker there. Using this way you must create your "work queue" with something similar to your state variables (_working, _done, wait conditions, etc), because the thread will exit if it leaves run(), you must pause/resume yourself.
I am coding a fairly simple application that uses Qt with OpenCV. I have single window that contains a widget which displays a video feed captured from a webcam. The webcam video capture is running in an infinite loop in a separate thread so as not to consume the UI thread.
When I close the window (using the normal "X" button on the top right of the window - this app is being developed in Windows 7), it doesn't seem to be shutting down the program correctly. The window does close visibly, but I put a breakpoint in the destructor of the main window, and the breakpoint never gets hit. Additionally, the thread which does video capture continues to run (I know this because the thread outputs to stdout periodically). Only when I click "stop debugging" in the Qt development environment does it cause everything to completely shut down.
Here is my worker object (not subclassing from QThread):
class Worker : public QObject
{
Q_OBJECT
private:
VideoCapture *cap;
bool finished;
QMutex mutex;
public:
Worker ()
{
cap = new VideoCapture(0);
finished = false;
}
bool isFinished ()
{
QMutexLocker locker (&mutex);
return finished;
}
public slots:
void doWork ()
{
Mat frame;
while(!isFinished())
{
// ...some code that outputs to stdout deleted for clarity...
(*cap) >> frame;
emit resultReady(frame);
}
}
void setFinished (bool f)
{
QMutexLocker locker (&mutex);
finished = f;
}
signals:
void resultReady (Mat frame);
};
Here is the header file for my main window:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
CVImageWidget* imageWidget;
Worker *worker;
QThread workerThread;
public slots:
void handleResults (Mat frame);
signals:
void operate ();
void finishSignal (bool f);
private:
Ui::MainWindow *ui;
};
And the class implementation:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//Create a widget for this window.
QWidget *wdg = new QWidget(this);
QGridLayout *grid = new QGridLayout(wdg);
// ...code creating widgets deleted for clarity...
this->setCentralWidget(wdg);
//Start video capture
qRegisterMetaType<Mat>("Mat");
worker = new Worker();
worker->moveToThread(&workerThread);
connect(&workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(this, SIGNAL(operate()), worker, SLOT(doWork()));
connect(worker, SIGNAL(resultReady(Mat)), this, SLOT(handleResults(Mat)));
connect(this, SIGNAL(finishSignal(bool)), worker, SLOT(setFinished(bool)));
workerThread.start();
emit operate();
}
MainWindow::~MainWindow()
{
emit finishSignal(true);
workerThread.quit();
workerThread.wait();
delete ui;
}
void MainWindow::handleResults(Mat frame)
{
imageWidget->showImage(frame);
}
Any help understanding why the program doesn't shut down properly would be appreciated. Thanks!