I'm trying to correct a large program for memory leaks and threads that are not stopped. I know I have some, but I'm not sure about how to properly identify and kill them, so I started playing with some canonical examples, and I'm already having those.
First I tried the simplest thing:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
return a.exec();
}
That gives me one (1) running thread in the Task Manager.
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne *w = new WorkerOne();
QTimer::singleShot(3456, w, SLOT(stop()));
return a.exec();
}
This one gives me 1 before starting the worker, then 2 until the thread actually starts (process is called), then 3 until the singleShot signal is captured and the worker deleted and then 2 again. So I'm having something loose there.
And this is the code for WorkerOne:
WorkerOne::WorkerOne(QObject *parent)
: QObject(parent)
, m_stop(false) {
QThread* thread = new QThread;
this->moveToThread(thread);
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), this, SLOT(process()));
connect(this, SIGNAL(finished()), thread, SLOT(quit()));
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
WorkerOne::~WorkerOne() {}
void WorkerOne::process() {
while(!m_stop) {
QEventLoop loop; QTimer::singleShot(1000, &loop, SLOT(quit())); loop.exec();
}
emit finished();
}
void WorkerOne::stop() {
m_stop = true;
}
void WorkerOne::errorString(QString err) { }
The platform is Qt 5.2.1 with mingw48_32 compiler.
I think I am following the steps in threading howto from Maya Posch's blog, but maybe I am missing something.
Your implementation of the worker object is literally upside down. It's QThread's job to spin the event loop. Your worker object should simply be driven by slot calls and incoming events. A processing busy loop idiom uses a zero-length timer to stay active while allowing the event loop to receive events and quit, with no need for extra flags.
Here's how to do it:
class WorkerOne : public QObject {
Q_OBJECT
QBasicTimer m_timer;
void processChunk() {
...
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId()) processChunk();
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() { m_timer.start(0, this); }
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne worker;
QThread thread;
thread.start();
worker.start();
worker.moveToThread(&thread);
a.connect(&thread, SIGNAL(finished()), SLOT(quit()));
QTimer::singleShot(3456, &thread, SLOT(quit()));
return a.exec();
}
When the timer times out, the thread's event loop quits, the thread finishes, the application's event loop is quit, and, finally, the thread and the worker get destroyed.
A zero-length timer is not really a timer, just an idiom that means: invoke me as soon as the event loop is entered and there's nothing else to do. Doing the below would be a premature pessimization as there's be a memory allocation per each round through the event loop - not using the timer would be worse!
class WorkerOne : public QObject {
Q_OBJECT
Q_INVOKABLE void processChunk() {
...
// A lame attempt to call ourselves again from the event loop.
// It works, but has lot more overhead than a zero-length timer!
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() {
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
};
Related
My code has following structure:
include
-> myserver.h
-> mythread.h
-> mainwindow.h
src
-> myserver.cpp
-> mythread.cpp
-> mainwindow.cpp
main.cpp
MyServer class creates a new thread for each connection. In that thread, I am reading the data from the client and want to send it to mainwindow.cpp. For this, I am thinking of using signal and slots. Since I have not declared MyThread in mainwindow, I am not able to use connect().
mythread.h:
signals:
void newDataRecieved(QVector<double> x,QVector<double> y);
mythread.cpp:
void MyThread::func(){
.
.
.
emit newDataRecieved(x,yC);
}
myserver.cpp:
void MyServer::incomingConnection(qintptr socketDescriptor)
{
// We have a new connection
qDebug() << socketDescriptor << " Connecting...";
MyThread *thread = new MyThread(socketDescriptor, this);
// connect signal/slot
// once a thread is not needed, it will be beleted later
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
mainwindow.h:
public slots:
void newValues(QVector<double> x,QVector<double> y);
main.cpp:
.
.
#include "myserver.h"
int main(int argc, char *argv[])
{
.
.
w.show();
MyServer server;
server.startServer();
return a.exec();
}
Is there any way to solve this?
Create a signal
void newDataRecieved(QVector<double> x,QVector<double> y);
In MyServer class and then connect the signal newDataRecieved form MyThread to the same signal of MyServer. Then in mainwindow connect a slot to the signal form MyServer.
Is there a way trigger a signal from another signal in Qt?
[EDIT]
Something like this:
myserver.h:
signals:
void newDataRecieved(QVector<double> x,QVector<double> y);
myserver.cpp:
void MyServer::incomingConnection(qintptr socketDescriptor)
{
// We have a new connection
qDebug() << socketDescriptor << " Connecting...";
MyThread *thread = new MyThread(socketDescriptor, this);
// connect signal/slot
// once a thread is not needed, it will be beleted later
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(newDataRecieved(QVector<double>, QVector<double>)), this, SIGNAL(newDataRecieved(QVector<double>, QVector<double>)));
thread->start();
}
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 am trying to write thread poll with QThread.
class ThreadPool: public QObject
{
Q_OBJECT
public:
ThreadPool(int maxThreads);
void addTask(MyTask *task);
private:
int maxThreads;
QMutex mutex;
QVector<QPair<bool, QThread>> threads;
QThread *getFreeThread();
public slots:
void freeThread();
};
void ThreadPool::addTask(MyTask* task)
{
QThread *thread = getFreeThread();
task->moveToThread(thread);
connect(thread, SIGNAL(started()), task, SLOT(doWork()));
connect(task, SIGNAL(workFinished()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), task, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), this, SLOT(freeThread()));
thread->start();
}
I am creating a limited number of threads in which I want to perform tasks.
However, I do not understand how to get the number of the freed thread.
I know about QThreadPool and Qtconcurrent, but I dont want to use it.
Perhaps, it is worth noting at each thread in QPair's vector is it free or not.
you do not really need a QVector<QPair<bool, QThread>> to keep track of all the threads in your Pool, instead use a QList< QThread* > which holds only the pointers to the free threads.
private:
QList<QThread*> freeThreads; // only free threads
QList<QThread*> allThreads; // just to count the number of all threads
In the slot freeThread() use the sender() method from QObject to get the pointer of the signal sender, which in this case will be the QThread, that has become free
void ThreadPool::freeThread()
{
// get the pointer to the thread that sent the signal:
QObject* threadFreed = QObject::sender();
if( ! freeThreads.contains( threadFreed ) )
{
// save the thread pointer in list
freeThreads << threadFreed;
}
}
Finally getFreeThread() can look like this:
QThread* getFreeThread()
{
if( ! freeThreads.isEmpty() )
{
// take the first free thread
return freeThreads.takeFirst();
}
else
{
if(allThreads.size() < maxThreads )
{
// create a new thread
QThread* thread = new QThread(this);
allThreads << thread;
return thread;
}
else
{
// Maximum number of threads exceeded
// and no free thread is available
return NULL;
}
}
}
Also you should handle the case when a NULL pointer is returned in addTask:
void ThreadPool::addTask(MyTask* task)
{
QThread *thread = getFreeThread();
if( ! thread )
{
// do something else
return;
}
// proceed with thread execution ...
}
I have a main class that launches a thread that performs a single action. I am trying to catch when the thread operations finish.
The main class:
// .h
class MainClass : public QObject
{
Q_OBJECT
public:
QThread thread;
// ...
public slots:
void onFinish();
}
// .cpp
void MainClass::startThread()
{
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(worker, SIGNAL(finished()), this, SLOT(onFinish()));
// connect(worker, SIGNAL(finished()), this, SLOT(onFinish()), Qt::DirectConnection);
}
void MainClass::onFinish()
{
std::cout << "Finished!" << std::endl << std::flush;
}
The Worker class for the thread:
// .h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0);
~Worker();
public slots:
void process();
signals:
void finished();
}
// .cpp
void Worker::process()
{
// ...Do stuff...
emit finished();
}
Executing startThread does not print "Finished!". Why?
I have noticed that if I add Qt::DirectConnection to the line that connects to onFinish() (like in the commented line), the message is printed. But what can I do if I want to execute the onFinish() actions in the thread of the main class?
Edit 1
In addition, it seems that the finished() -> quit() connect is also not working, because if I call thread->isFinished() or thread->isRunning(), after sleeping in the main thread to be sure that the thread task is completed, I obtain false and true, respectively.
Edit 2
Since it may also be relevant, here is the main.cpp:
int _tmain(int argc, _TCHAR* argv[])
{
QCoreApplication a(argc, argv);
std::unique_ptr <MainClass> mc = std::make_unique <MainClass>();
mc->startThread();
mc->thread->wait();
return a.exec();
}
On a first look I would say that the order of connections is important. The deleteLater() slots should always be the last methods.
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), this, SLOT(onFinish()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
Sitenode - QRunnable
You might consider to use QRunnable instead, which is designed for short running tasks/jobs. You can combine them with QObject or QFuture/QFutureWatcher to get notified as soon as they a finished.
Update 1
Your main-event loop never starts and it looks like you want to exit the application when the task finishes. I don't think this is a nice implementation but these modifcations should work for you:
int _tmain(int argc, _TCHAR* argv[])
{
QCoreApplication a(argc, argv);
std::unique_ptr<MainClass> mc = std::make_unique<MainClass>();
mc->startThread();
// do not wait!
// let the main-event-loop handle events -> a.exec()
// and quit() application by signal/slot
return a.exec();
}
void MainClass::startThread()
{
thread = new QThread();
worker = new Worker();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), this, SLOT(onFinish()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), qApp, SLOT(quit()));
}
void MainWindow::on_pushButton_clicked()
{
QFuture<int> future = QtConcurrent::run(identify); //Thread1
if (future.isFinished())
{
//DoSomething();
}
}
I have this code. I want to run the DoSomething() function after the identify function finished running. Is it possible?
You can pass the QFuture object to a QFutureWatcher and connect its finished() signal to the function or slot DoSomething().
For example:
void MainWindow::on_pushButton_clicked()
{
QFuture<int> future = QtConcurrent::run(identify); //Thread1
QFutureWatcher<int> *watcher = new QFutureWatcher<int>(this);
connect(watcher, SIGNAL(finished()), this, SLOT(doSomething()));
// delete the watcher when finished too
connect(watcher, SIGNAL(finished()), watcher, SLOT(deleteLater()));
watcher->setFuture(future);
}
void MainWindow::DoSomething() // slot or ordinary function
{
// ...
}
Or you could use a nested event loop to keep the GUI responsive and have everything inside the same function:
void MainWindow::on_pushButton_clicked()
{
QFuture<int> future = QtConcurrent::run(identify); //Thread1
QFutureWatcher<int> watcher;
QEventLoop loop;
// QueuedConnection is necessary in case the signal finished is emitted before the loop starts (if the task is already finished when setFuture is called)
connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()), Qt::QueuedConnection);
watcher.setFuture(future);
loop.exec();
DoSomething();
}
I like this call layout.
auto watcher = new QFutureWatcher<int>(this);
connect(watcher, &QFutureWatcher<int>::finished,
[watcher, this] ()
{
watcher->deleteLater();
auto res = watcher->result();
// ...
});
watcher->setFuture(QtConcurrent::run(identify, param1, param2));