How to delete tied objects in Qt? - c++

There are two classes: Widget and Worker. Here is a schematic code.
class Widget
{
Worker *m_worker;
QTextEdit *m_edit;
public:
Widget():m_edit(new QTextEdit){}
~Widget()
{
m_worker->ShouldStop = true;
delete *m_worker;
}
void doWork()
{
m_worker = new Worker;
if (!worker->doWork())
m_edit->setText("failed");
}
}
class Worker
{
Worker() : ShouldStop(false){}
public:
bool ShouldStop;
bool doWork()
{
while(true && !ShouldStop)
{
QThread::sleep(1);
QApplication::processEvents();
}
//consider the work undone if a stop was forced
if (ShouldStop)
return false;
}
}
After a call to doWork() of the Widget the execution loops in the method doWork() of the Worker. A widget is then closed and its destructor is called during one of the calls to processEvents(). Then the execution then returns to the doWork() of the Worker.
It now checks ShouldStop and returns to the doWork() of the Widget and tries to add something to the m_edit. However the Widget object is already dead.
Questions:
How can a Worker be deleted cleanly?
What is the best design to avoid such an interplay?

Ideally, worker threads should just return data via the signals and slots mechanism, not directly accessing the original object. Actually creating a thread and avoiding the call to QApplication::processEvents() is the first way to avoid the problem.
Additionally, you should consider using a design like this when you want to start a worker in a new thread. Rather than subclassing QThread, you can just create a generic QThread and assign a QObject to it, like so:
Worker *worker = new Worker;
QThread *workerThread = new QThread(this);
connect(workerThread, &QThread::started, worker, &Worker::doWork);
connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);
worker->moveToThread(workerThread);
// Starts an event loop, and emits workerThread->started()
workerThread->start();
Consider restructuring your code around this pattern if you're using Qt 5.

#Alex answer is definitely the way to go for q2. He just forgot to mention how to proceed for the deletion (q1). Assuming Widget created the object workerThread, then this is necessary:
~Widget(){
if(workerThread->isRunning()){
workerThread->terminate(); <--- this line, right there
workerThread->wait():
}
...
}
Why? Because deleting a QThread just delete the thread object but doesn't stop the thread from running, and may crash the application. Note that if you are using
connect(workerThread, &QThread::finished, worker, &Worker::deleteLater);
as Alex mentioned, then it is not safe to access worker after the call to terminate, because it will trigger the finished() signal ,execute worker->deleteLater, and eventually delete worker.

You could have Widget use a signal to inform the owner of Widget to start up Worker for the Widget.
Owner owns both Widget and Worker. Widget tells Owner that something was triggered, and Owner is responsible for deciding that Worker's doWork() is the correct response, and for managing the lifetime of both Worker and Widget. Worker and Widget are ignorant of each other, but Owner might connect some of their signals and slots together.

Related

What is the correct way to write data to a file using worker thread in Qt?

I am developing an application in Qt, which is UI intensive. It is UI intensive because, my application displays logs,which come at a very high speed and UI has to reflect that.
Now after the number of logs exceed a certain amount, My previous logs will start to get deleted, because my UI window has a limit(100000 logs, to keep app fast).
So in order to save the old logs , I want to write the old logs to a file, before they get deleted.
Problem
If I write the file in main thread,my UI hangs(becomes very slow). So I decided to write file in a worker thread. This is what I did this:
I made my own class WorkerThread that inherits class QThread and inside that class run() method, I write the data to a file.
The data that I want to write is stored in threads member variables itself:
So my code is:
Some other class function
.
.
.
.
WorkerThread *workerThread = new WorkerThread();
connect(workerThread, SIGNAL(resultReady()), workerThread, SLOT(quit()));
workerThread->attribute1 = dataToWrite1;
workerThread->attribute2 = dataToWrite2;
workerThread->start();
WorkerThread class
class WorkerThread : public QThread
{
Q_OBJECT
public:
QString attribute1;
QString attribute2;
protected:
void run() {
// DELIMITER IS ..: //
QFile myFile("C:/shiftedlines/myFile.txt");
if(myFile.open(QIODevice::WriteOnly|QIODevice::Append))
{
QTextStream stream(&myFile);
stream<< attribute1<<"..:";
stream<< attribute2<<"\n";
}
emit resultReady();
}
signals:
void resultReady();
};
But after writing about 500 lines, my application crashes. How do I go about solving this problem?
This does not address the issue you are having but since you asked this in the comments, this is how I implemented such tasks in the past.
worker class
class worker : public QObject
{
Q_OBJECT
public:
worker();
public slots:
void start();
signals:
void finished();
};
main
worker* cur_worker = new worker();
// move to its own thread
QThread* worker_thread = new QThread(this);
cur_worker->moveToThread(worker_thread);
QObject::connect(worker_thread, SIGNAL(started()), cur_worker, SLOT(start()));
QObject::connect(cur_worker, SIGNAL(finished()), worker_thread, SLOT(quit()));
QObject::connect(worker_thread, SIGNAL(finished()), worker_thread, SLOT(deleteLater()));
// start
worker_thread->start();
This example does not handle the destruction of the worker object, which in your case you probably want to do immediately.
Writing to a file should be quite fast as long as it's done correctly.
What is slow is not writing to the file, but opening it.
Make sure you don't open / close the file each time you receive a log, but open the file in write only and append mode, and keep it open while your application is running and writing log.
Usually you can write in recent SSD drive at a speed around 700MB/s of data, so I doubt that you would have any noticeable impact on the UI.
If you really want to go for thread (which IMO is probably overkill) don't forget that to be thread safe, you have to communicate with your thread using signals / slots.
From your code, it seems you start a new thread for each log write, which each tries to open the file. Your file can be written only by one thread at a time and this will be blocked by the system, so above 1 thread for writing into a file, it is useless to have more.
Probably your threads hangs into trying to open the file which is already accessed by some other, and end up with hundreds of hanging threads which ends up in a memory overflow if you have them in the stack.
The roule of Open your file once and write as long as you have something to write also applies in the thread.

Qt can't figure out how to thread my return value in my program

I have read various articles on the web relating to how to multithread applications in Qt such as the article here and I've noticed Qt have also updated their official documentation on the subject, however I am still struggling to understand how I can create a thread, do some image processing and return a new QImage to update my GUI.
The things I am struggling to get clarification on are:
Where do I put my connect code, in most examples I see the connections declared in the constructor of the object.
Why does a connect statement require so many lines to do one process? I.e. In my case I have a slider to change the saturation of an image on a QGraphicsView, I want to spawn a thread to handle the manipulation of images pixels and then return the formatted QPixmap to my GUI and run a render method to draw the new image to the canvas (I don't think I can update my canvas from my thread?)
Following point 2, here is the current code I have written for my thread (I am not subclassing QThread and I think I am following the documentation correctly.)
WorkerThread.h
#include "sliders.h"
class WorkerThread : public QObject
{
Q_OBJECT
public:
WorkerThread();
~WorkerThread();
public slots:
void modifySaturation(const int, const QPixmap);
signals:
void SaturationChanged(const QPixmap);
private:
Sliders *slider;
};
WorkerThread.cpp
WorkerThread::WorkerThread()
{
}
WorkerThread::~WorkerThread()
{
}
// Create a new Sliders object on the thread (declaring in construct would place it on the main thread?)
// Call the modifySaturation() method in the slider class and store its returned QPixmap into the variable to emit it back to the GUI
void WorkerThread::modifySaturation(const int value, const QPixmap image)
{
slider = new Sliders;
QPixmap img = slider->modifySaturation(value, image);
emit resultReady(img);
}
Hopefully the comments above convey what I wish to do in terms of emitting the newly created Pixmap back to main thread to draw to the GUI.
The step I am having troubles with is writing the logic to bridge the connection between my main thread and worker thread, so far I have created a QThread object called 'thread' in my mainwindow.h, then in my mainwindow.cpp I do the following:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// Instanciate a scene object that we can draw to and then set up the ui
scene = new QGraphicsScene(this);
filter = new Filters;
worker = new WorkerThread;
ui->setupUi(this);
thread = new QThread;
worker->moveToThread(&thread);
// This is what I am struggling to understand
connect(thread, SIGNAL(started()), worker, SLOT(modifySaturation(int,QPixmap)));
connect(worker, SIGNAL(SaturationChanged(QPixmap)), MainWindow, SLOT(onSaturationChanged()));
}
// Public slot on my main window to update the GUI
void MainWindow::onSaturationChanged(QPixmap)
{
// image is a private member describing the current loaded image
m_image = QPixmap;
renderImageToCanvas();
}
From what I have read, I am supposed to spawn a new thread when I start a task, but how can I:
Reuse this thread for multiple methods (change saturation, change brightness, change hue...), do I need to create a new thread for every different task (this seems a bit over complicated)?
How can I connect the value changed method of my saturation slider to launch the computation on a new thread and then return it to update the GUI using the OnSaturationChanged slot in my main window?
As you've mentioned the great article How To Really Truly use QThread, let's start with explaining the code that you're unsure about by breaking this down
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()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
This code will usually be placed in an object on the main thread, perhaps in the MainWindow: -
Create a new thread object - QThread is actually more of a thread controller than a thread
QThread* thread = new QThread;
Create a new worker object. This is an object which will do work on a different thread. As this can be moved to a different thread, note that you can create multiple objects and move them to the same thread
Worker* worker = new Worker();
Move the object and its children to the new thread
worker->moveToThread(thread);
Setup useful connections to monitor and control the worker. Let's start with any errors, so we know if the worker had a problem
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
In order to start the worker object processing, we connect the started() signal of the thread to the process() slot of the worker. In your example, process would be the modifySaturation slot
connect(thread, SIGNAL(started()), worker, SLOT(process()));
When the worker has finished processing, if it is the only object, it needs to quit and clean up, so the thread should quit
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
In order to tidy up, now both the worker and thread are no longer needed, make sure they tidy up after themselves
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
Finally, let's get going by calling thread->start(), which will trigger the initial started() signal, which we previously connected to the worker's process() function
thread->start();
With all that in mind, let's tackle the questions posed: -
1 How can I reuse this thread for multiple methods (change saturation, change brightness, change hue...), do I need to create a new thread for every different task (this seems a bit over complicated)?
No, you do not need a new thread for each method. You can either use the current object and extend that to do all the processing, controlling it via signals and slots from the main thread, or you could create a separate object for each method and move them all to the new thread.
If you use multiple objects that are moved to the new thread, ensure that you don't connect an object's finished() signal to call quit() on the thread if other objects are still using that thread. However, you will still need to cleanup the objects and thread when you've finished with them.
2 Why does a connect statement require so many lines to do one process? i.e. in my case I have a slider to change the saturation of an image on a QGraphicsView, I want to spawn a thread to handle the manipulation of images pixels and then return the formatted QPixmap to my GUI and run a render method to draw the new image to the canvas (I don't think I can update my canvas from my thread?)
The general rule is that you can only update graphical objects (widgets, graphics items etc.) from the main thread. (There is an exception, but it's beyond the scope of this discussion and irrelevant here.)
When using just one object, of the multiple connect signals, three are used to delete the objects when finished, one for handling error messages and the final connect ensures that the worker object starts when the thread begins.
There is nothing stopping you changing this by creating your thread and starting it first, creating worker objects, connecting relevant signals and moving them to the thread afterwards, but you'd need to trigger the workers to start doing something, such as processing the saturation, once they've been moved to the new thread.
QThread* pThread = new QThread;
pThread->start();
Worker* worker1 = new Worker();
Worker* worker2 = new Worker();
Worker* worker3 = new Worker();
worker1->moveToThread(pThread);
worker2->moveToThread(pThread);
worker3->moveToThread(pThread);
The worker objects here have been moved to the new thread, which is running. However, the worker objects are idle. Without a connection, we can invoke a slot to be called. Let's assume that the process slot takes an integer parameter...
QMetaObject::invokeMethod( worker1, "process", Q_ARG( int, param ) );
QMetaObject::invokeMethod( worker2, "process", Q_ARG( int, param ) );
QMetaObject::invokeMethod( worker3, "process", Q_ARG( int, param ) );
So, as you see here, you don't always need to connect signals, but it is convenient.
I will answer one of your questions as Merlin covered the rest pretty well.
how can I connect the value changed method of my saturation slider to launch the computation on a new thread and then return it to update the GUI using the OnSaturationChanged slot in my main window?
Well for example, in your MainWindow::OnSaturationChanged slot you could emit a signal that passes the QImage and the slider value to your thread. This signal would be connected to a slot of your WorkerThread which does some image manipulation.
mainwindow.h
public slots:
void addNewImage(QImage image);
signals:
void requestImageUpdate(QImage image, int sliderValue);
mainwindow.cpp
//in your MainWindow constructor or wherever you create your worker...
connect(this, SIGNAL(requestImageUpdate(QImage, int)), worker, SLOT(updateImage(QImage, int)));
connect(worker, SIGNAL(imageUpdated(QImage)), this, SLOT(addNewImage(QImage)));
...
void MainWindow::OnSaturationChanged()
{
emit requestImageUpdate(myImage, slider->value());
}
void MainWindow::addNewImage(QImage image)
{
//update the image in your graphics view or do whatever you want to do with it
}
workerthread.h
public slots:
void updateImage(QImage image, int sliderValue);
signals:
void imageUpdated(QImage newImage);
workerthread.cpp
void WorkerThread::updateImage(QImage image, int sliderValue)
{
QImage newImage; // you might no need this, this is just an example
....
emit imageUpdated(newImage);
}
P.S. Use QPixmap only in the main thread. In other threads use QImage.

QT GUI freezes even though Im running in separate thread

I have a small chat application where I use a SQLite database to store all the conversations. I've noticed that the app freezes randomly, and I then have to minimize and maximize it to make it work again. I thought that the problem might be the SQLite selects / inserts that were causing the gui to freeze. I decided to try and move all the SQLite methods into a separate thread.
After doing so the app still freezes.
Some things that might be worth knowing:
I use QTcpSocket directly in my MainWindow but it seems that there is no use in running the QTcpSocket in a separate thread?
I have separated the SQLite methods into a new thread (see implementation below)
I use 3 WebViews for displaying my chat messages, the entire application GUI is build with these WebViews
Does my code below really run in a separate thread? GUI still freezes.
My header file:
class dbThread : public QObject
{
Q_OBJECT
public:
dbThread(QObject* parent);
public slots:
bool openDB(QString agentID);
signals:
void clearPreviousHistory();
private:
QSqlDatabase db;
QHash<QString, QString> countries;
};
My cpp file:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QThread* thread = new QThread(this);
dbtrad = new dbThread(this);
dbtrad->moveToThread(thread);
dbtrad->openDB(userID);
connect(dbtrad, SIGNAL(clearPreviousHistory()), this, SLOT(clearHistoryV()));
thread->start();
}
dbThread::dbThread(QObject * parent): QObject(parent) {
}
bool dbThread::openDB(QString agentID) {
qDebug() << "OPEN DB FROM THREAD ";
// Find QSLite driver
db = QSqlDatabase::addDatabase("QSQLITE");
// ......
}
This is how I call dbThread methods from my MainWindow:
dbtrad->getHistory(channelId);
Edit
New code:
// Start database thread
QThread* thread = new QThread(this);
dbtrad = new dbThread(this);
dbtrad->moveToThread(thread);
connect(this, SIGNAL(requestOpenDB(QString)), dbtrad, SLOT(openDB(QString)));
thread->start();
emit requestOpenDB(userID);
dbtrad->openDB(userID); will execute like any normal function (Why should it?), in the GUI thread.
moveToThread allow you to execute slots called using signals in a separate thread.
If you want to execute openDB in the thread you can trigger its execution using
connect (thread, SIGNAL(started()), dbtrad, SLOT(openDBWithUIDAlreadySet()))
or
connect (this, SIGNAL(requestOpenDB(int)), dbtrad, SLOT(openDB(int)))
You need to use existing or additional signals. Qthread::start() emit the signal started(). You can also define
MainWindow{
signals:
void requestOpenDB(int);
void queryHistory(int channelid);
}
and emit the signals manually using
emit requestOpenDB(userID); //for openDB
emit queryHistory(channelId); // for getHistory
the responses from the dbThread object also need to be given using a signal which is connected to a slot. Like a notification.
QTcpSocketdoes indeed not need to be in a separated thread.
as long as all the database access is done from that thread where the database was created it should also be no problem
And now to the fun part: i think you create the database in the main thread ... by calling dbtrad->openDB(userId)
Yes so qt moveToThread() does not do what you are expecting it to do. The function that you are calling from your main thread will get executed in your main thread only. That database access is causing GUI freezes.
moveToThread only moves "event processing" in a seperate thread. Which means any slots of dbThread which are connected using Qt::QueuedConnectionwill get executed in new thread.
Following way will execute getHistory() method in your main ui thread only. You need to create a signal in main thread and make getHistory() a slot of dbThread class. Then connect both.
Reading documentation AND logs is essential!!!
In log you have a warning that YOU CAN"T MOVE TO THREAD IF OBJECT HAVE A PARENT.
Also documentation clearly says that:
Changes the thread affinity for this object and its children. The
object cannot be moved if it has a parent. Event processing will
continue in the targetThread.
Proper way to fix it:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
thread = new QThread(this);
dbtrad = new dbThread(); // NO PARENT
dbtrad->moveToThread(thread);
// run object method in thread assigned to this object:
QMetaObject::invokeMethod(dbtrad, "openDB", Qt::QueuedConnection, Q_ARG(QString, userID));
connect(dbtrad, SIGNAL(clearPreviousHistory()), this, SLOT(clearHistoryV()));
thread->start();
}
MainWindow::~MainWindow()
{
dbtrad->deleteLater();
thread->quit();
thread->wait(5000); // wait max 5 seconds to terminate thread
}

Want to put a method into a QThread

How to add a method within the class to a thread to execute?
I do not want to put "Pup" into a seperate class that inherits QThread as this is just an abstraction of some Legacy code I am working on.
void Dog::Pup()
{
printf("pup");
}
void Dog::Init()
{
QThread *dogThread = new QThread();
Pup->moveToThread(dogThread); //this is all wrong
Pup->connect(dogThread, ?, Pup, SLOT(Pup), ?)
dogThread.start();
}
Try this:
void Dog::Init()
{
QThread *dogThread = new QThread;
connect(dogThread, SIGNAL(started()), this, SLOT(Pup()), Qt::DirectConnection);
dogThread->start();
}
It basically creates a new QThread named dogThread and connects it's started() signal to the method you want to run inside the thread (Dog::Pup() which must be a slot).
When you use a Qt::QueuedConnection the slot would be executed in the receiver's thread, but when you use Qt::DirectConnection the slot will be invoked immediately, and because started() is emitted from the dogThread, the slot will also be called from the dogThread. You find more information about the connection types here: Qt::ConnectionType.
if you want to run a single function in another thread, you should check out the methods in the QtConcurrent namespace.
Read the Detailed description in the page http://doc.qt.io/qt-5/qthread.html

start doesn't invoke run

I'm trying to implement some small app which is a gui app and has some heavy work to do as a one of it's main tasks. Obviously I'm putting this "work" into a separate thread and starting this thread by invoking start fnc on this obj. Unfortunatelly nothing happens. On the other hands when instead of start I invoke implemented fnc run computations are performed as they should although of course in same thread as gui. What to do?
So I have class inheriting QThread:
class Working_Thread : public QThread
{
Q_OBJECT
public:
typedef boost::filesystem3::path path_t;
private:
bool& cancel_flag_;
const std::set<path_t>& paths_;
int search_depth_;
typedef void (Dir_File_Select_Dialog::*fnc_ptr)(const std::set<path_t>&,int);
fnc_ptr fnc_;
Dir_File_Select_Dialog* parent_;
protected:
void run()
{
(parent_->*fnc_)(paths_,search_depth_);
}
public:
Working_Thread(bool& cancel_flag,const std::set<path_t>&,int&,fnc_ptr fnc,Dir_File_Select_Dialog* parent);
};
And here is fragment from gui thread when I try to start new thread:
Working_Thread* working_thread = new Working_Thread(cancel_flag,paths,search_depth,&Dir_File_Select_Dialog::extract_files_,this);
working_thread->start();//this desn't invoke run fnc
but when I do:
working_thread->run();//this will perform computations although in gui thread
UPDATE:
Little change I did which now performs computations when using start fnc but it still blocks GUI.
Working_Thread* working_thread = new Working_Thread(cancel_flag,paths,search_depth,&Dir_File_Select_Dialog::extract_files_,this);
working_thread->start();//hangs
working_thread->wait();//when I call wait here computation is performed but GUI is blocked.
I don't know how your code is actually done, but as a first step i suggest you to follow the best practice suggested at the end of the new revision of the Qt documentation of QThread :
http://qt-project.org/doc/qt-4.8/QThread.html (look for bottom of this page)
For a similar tutorial you also may check this article: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Every time i tried to directly make my treatment in a QThread I ended up having big problems with threads (most of time, the treatment beeing done in the caller's tread).
This documentation has been added in 4.8 and the examples provided by documentation of previous versions were missleading.
(code copied from the Qt documentation)
Consider the following pattern as your default way to use QThread:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork() {
/* ... */
}
};
/* ... */
QThread *thread = new QThread;
Worker *worker = new Worker;
//obj is a pointer to a QObject that will trigger the work to start. It could just be this
connect(obj, SIGNAL(startWork()), worker, SLOT(doWork()));
worker->moveToThread(thread);
thread->start();
//obj will need to emit startWork() to get the work going.
Alternatively, you could do:
//based on the same Worker class as above:
/* ... */
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
It is normal that the GUI blocks if you call wait() on a thread, because this will wait for the thread to finish, and also you haven't specified any timeout for wait in this case.
Now regarding the initial problem (when you don't call wait()), I have used QThread successfully in similar scenarios. I do not know though what is wrong in your code, but what I would check is if your execution doesn't hang in other places, like in the invocation of
(parent_->*fnc_)(paths_,search_depth_);
So maybe inserting some log / debug message before and after this call, and also in the function that is invoke here might help isolating the problem. At least then you'll know if the run() method is invoked or not. For example:
qDebug() << "In thread.run()";
(parent_->*fnc_)(paths_,search_depth_);
qDebug() << "In thread.run(), calculations are done";
Also I find it suspicious that you perform calculation using a GUI object (Dir_File_Select_Dialog). This is not normal in Qt, Gui objects should normally be used in the GUI thread. Why not implement the calculations directly in run? Or at least move it to a non-GUI object, just to be sure and keep GUI implementations separated from background operations.
If you call wait, the GUI is going to be blocked.
If this program hangs when you do a start, it seems that the problem is in this call: (parent_->*fnc_)(paths_,search_depth_);
You could place a qDebug call just before and after this call.