Qt - updating main window with second thread - c++

i have an multithreaded qt application. when i am doing some processes in mainwindow.cpp, at the same time, i want to update mainwindow.ui from other thread.
i have mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include "mainwindow.h"
class mythread : public QThread
{
public:
void run();
mythread( MainWindow* ana );
MainWindow* ana;
private:
};
#endif // MYTHREAD_H
mythread.cpp
mythread::mythread(MainWindow* a)
{
cout << "thread created" << endl;
ana = a;
}
void mythread::run()
{
QPixmap i1 (":/notes/pic/4mdodiyez.jpg");
QLabel *label = new QLabel();
label->setPixmap(i1);
ana->ui->horizontalLayout_4->addWidget(label);
}
but the problem is that, i cannot reach the ana->ui->horizontalLayout_4->addWidget(label);
how can i do that?

but the problem is that, i cannot reach the
ana->ui->horizontalLayout_4->addWidget(label);
Put your UI modifications in a slot in your main window, and connect a thread signal to that slot, chances are it will work. I think only the main thread has access to the UI in Qt. Thus if you want GUI functionality, it must be there, and can be only signaled from other threads.
OK, here is a simple example. BTW, your scenario doesn't really require to extend QThread - so you are better off not doing it, unless you really have to. That is why in this example I will use a normal QThread with a QObject based worker instead, but the concept is the same if you subclass QThread:
The main UI:
class MainUI : public QWidget
{
Q_OBJECT
public:
explicit MainUI(QWidget *parent = 0): QWidget(parent) {
layout = new QHBoxLayout(this);
setLayout(layout);
QThread *thread = new QThread(this);
GUIUpdater *updater = new GUIUpdater();
updater->moveToThread(thread);
connect(updater, SIGNAL(requestNewLabel(QString)), this, SLOT(createLabel(QString)));
connect(thread, SIGNAL(destroyed()), updater, SLOT(deleteLater()));
updater->newLabel("h:/test.png");
}
public slots:
void createLabel(const QString &imgSource) {
QPixmap i1(imgSource);
QLabel *label = new QLabel(this);
label->setPixmap(i1);
layout->addWidget(label);
}
private:
QHBoxLayout *layout;
};
... and the worker object:
class GUIUpdater : public QObject {
Q_OBJECT
public:
explicit GUIUpdater(QObject *parent = 0) : QObject(parent) {}
void newLabel(const QString &image) { emit requestNewLabel(image); }
signals:
void requestNewLabel(const QString &);
};
The worker object is created and moved to another thread, then connected to the slot that creates the labels, then its newLabel method is invoked, which is just a wrapper to emit the requestNewLabel signal and pass the path to the image. The signal is then passed from the worker object/thread to the main UI slot along with the image path parameter and a new label is added to the layout.
Since the worker object is created without parent in order to be able to move it to another thread, we also connect the thread destroyed signal to the worker deleteLater() slot.

First and foremost, "you're doing it wrong". Normally you want to create a class derived from a QObject and move that class to a new thread object instead of deriving your class from a Qthread
Now to get onto the specifics of your question, you're not able to directly modify the ui elements of your main GUI thread from a separate thread. You have to connect a signal from your 2nd thread to a slot in your main thread. You can pass any data that you need through this signal/slot connection but you're unable to directly modify the ui element (which in all honestly you probably do not want to if you intend to keep the frontend of your app separate from the backend). Checkout Qt's signal and slot documentation for a whole lot more information

how can i do that?
You've already got the answers to what you should be doing, but not a why, so I'm going to add a why.
The reason you don't modify GUI elements from another thread is because GUI elements are usually not thread-safe. This means that if both your main GUI thread and your worker thread update the UI, you cannot be certain of the order of what happened when.
For reading data generally this can sometimes be fine (e.g. checking a condition) but generally you do not want this to be case. For writing data, this is almost always the source of very, very stressful bugs which occur "at random".
Another answer has remarked on good design principles - not only does constraining your GUI logic to one thread and firing signals to talk to it get rid of your race condition issues, but it also forces you to compartmentalize your code nicely. Presentation logic (the display bit) and data processing logic can then be cleanly separated out, which makes maintaining the two much easier.
At this stage you might think: heck, this threads business is farrrrrr too much work! I'll just avoid that. To see why this is a bad idea, implement a file copy program in a single thread with a simple progress bar telling you how far along the copy is. Run it on a large file. On Windows, after a while, the application will "go white" (or on XP I think it goes gray) and will be "not responding". This is very literally what is happening.
GUI applications internally mostly work on the variation of "one big loop" processing and dispatching messages. Windows, for example, measures response time to those messages. If a message takes too long to get a response, Windows then decides it is dead, and takes over. This is documented in GetMessage().
So whilst it may seem like quite a bit of work, Signals/Slots (an event-driven model) is basically the way to go - another way to think of this is that it is totally acceptable for your threads to generate "events" for the UI too - such as progress updates and the like.

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.

QTcpSocket in QThread will commitTransaction but when Write is called "Cannot create children for a parent that is in a different thread."

Disclaimer: I am relatively new to Qt and any type of programming that revolves around Threads and Networking. I have also adopted a lot of code from Qt Examples, API, and other online examples.
All code can be found on GitHub. This code is relatively as simple as it can get minus striping out GUI. I figure supplying it this way would help as well versus just pasting the code below.
I want to use and believe I need to use Threads as I need multiple clients send a request to the server, the server run some SQL code, then spit out the results back to the client (basically deriving a MySQL Server, but specific to what I am doing). Right now though, I am just working on learning the workings of it all.
With all that being said, as the Title states.. My client can connect to the server, the server sets up the thread, and will receive data (a String) through the readReady. After the data is read in, for right now I am just trying to echo it back to the client. It will do this, but only once. Then it spits out:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNativeSocketEngine(0x266cca92ea0), parent's thread is serverThread(0x266cca9ed60), current thread is QThread(0x266cac772e0)
I cannot send any further data to the server unless I have the client reconnect, then after the data is sent, it will do its job but then spit out the same error and cease functioning. I have tried quite a bit of different things, but cannot seem to fix the issue. I even tried setting up a SIGNAL/SLOT for this as suggested in API:
It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.
Anyway, any help would be greatly appreciated! My Code is below..
Server
ServerThread.cpp
// Project
#include "ServerDialog.h"
#include "ServerThread.h"
ServerThread::ServerThread(qintptr _socketDiscriptor, QObject *parent /*= 0*/)
: QThread(parent)
{
socketDiscriptor = _socketDiscriptor;
}
void ServerThread::run()
{
emit threadStarted(socketDiscriptor);
// Start Thread
clientSocket = new QTcpSocket;
// Set SocketDisc
if (!clientSocket->setSocketDescriptor(socketDiscriptor))
{
emit error(clientSocket->error());
return;
}
// Connect Socket and Signal
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(disconnected()));
//// Loop Thread to Stay Alive for Signals and Slots
exec();
}
void ServerThread::readyRead()
{
QDataStream in(clientSocket);
in.setVersion(QDataStream::Qt_5_7);
in.startTransaction();
QString dataReceived;
in >> dataReceived;
if (!in.commitTransaction())
{
emit readyReadError(socketDiscriptor);
return;
}
emit readyReadMessage(socketDiscriptor, dataReceived);
echoData(dataReceived);
}
void ServerThread::disconnected()
{
emit threadStopped(socketDiscriptor);
clientSocket->disconnect();
clientSocket->deleteLater();
this->exit(0);
}
void ServerThread::echoData(QString &data)
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_7);
out << data;
clientSocket->write(block);
}
So in ServerThread.cpp when echoData is called, that is when the error shows up and the Socket ceases functioning.
Any and all help will be appreciated. I know there are a few other posts regarding "Cannot create children for..." in regards to Threads. But I did not find any of them helpful. The one thing that I did find interesting but did not understand was maybe using moveToThread() but a lot of mixed comments on that.
I learn best through code examples along with explanation versus just an explanation or pointer to API. Thank you!
Most of Qt network functions are asynchronous; they do not block the calling thread. There is no need to mess up with threads if you are using QTcpSockets. In fact, creating a thread for every socket is an overkill, since that thread will spend most of its time just waiting for some network operation to finish. Here is how I would implement a single-threaded echo server in Qt:
#include <QtNetwork>
#include <QtCore>
//separate class for the protocol's implementation
class EchoSocket : public QTcpSocket{
Q_OBJECT
public:
explicit EchoSocket(QObject* parent=nullptr):QTcpSocket(parent){
connect(this, &EchoSocket::readyRead, this, &EchoSocket::EchoBack);
connect(this, &EchoSocket::disconnected, this, &EchoSocket::deleteLater);
}
~EchoSocket() = default;
Q_SLOT void EchoBack(){
QByteArray receivedByteArray= readAll();
write(receivedByteArray);
disconnectFromHost();
}
};
class EchoServer : public QTcpServer{
public:
explicit EchoServer(QObject* parent= nullptr):QTcpServer(parent){}
~EchoServer() = default;
//override incomingConnection() and nextPendingConnection()
//to make them deal with EchoSockets instead of QTcpSockets
void incomingConnection(qintptr socketDescriptor){
EchoSocket* socket= new EchoSocket(this);
socket->setSocketDescriptor(socketDescriptor);
addPendingConnection(qobject_cast<QTcpSocket*>(socket));
}
EchoSocket* nextPendingConnection(){
QTcpSocket* ts= QTcpServer::nextPendingConnection();
return qobject_cast<EchoSocket*>(ts);
}
};
int main(int argc, char* argv[]){
QCoreApplication a(argc, argv);
EchoServer echoServer;
echoServer.listen(QHostAddress::Any, 9999);
QObject::connect(&echoServer, &EchoServer::newConnection, [&](){
EchoSocket* socket= echoServer.nextPendingConnection();
qDebug() << "Got new connection from: " << socket->peerAddress().toString();
});
return a.exec();
}
#include "main.moc"
Notes:
This server has the ability to handle more than one client at the same time, since there is no blocking. The thread will just respond to the event that happens with the appropriate action; So, if that event was a new connection, it will create a new EchoSocket object to handle it and prints a statement out to qDebug(), and if that event was receiving something on a previously created socket, the same thread will echo received data back and close the connection. It will never block on a single connection waiting for data to arrive nor it will block waiting for a new connection to arrive.
Since you mention using some SQL queries in response for some connections later in your project. Please avoid threading since an SQL database connection in Qt can be used only from the thread that created it, see docs here. So, You'll have to either create a new database connection for each thread (and thus for each connection) in your application (and this is beyond just overkill), or switch later to a single threaded design.
In this section, I am explaining why threading does not work for you the way you are doing it:
You should not be declaring slots in your QThread subclass, Instead, use worker QObjects and move them to QThreads as needed.
The quote you have provided in your question is the exact explanation for why you get this warning. The ServerThread instance you create will be living in the main thread (or whatever thread that created it). Now let's consider this line from your code:
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
The signal readyRead() will be emitted from the current ServerThread instance (since the clientSocket object that emits it lives there), However, the receiver object is the current ServerThread instance, But that lives in the main thread. Here is what the documentation says:
If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used.
Now, the main point of Qt::QueuedConnection is executing the slot in the receiver object's thread. This means that, your slots ServerThread::readyRead() and ServerThread::disconnected will get executed in the main thread. This is most likely not what you meant to do, since you'll end up accessing clientSocket from the main thread. After that, any call on clientSocket that results in child QObjects being created will result in the warning you get (you can see that QTcpSocket::write() does this here).
Mixed comments of movetothread are linked mostly to usage of it to move thread object to itself.
The quote hints that the members of QThread aren't designed to be called from worker. Strictly proper way to call signal would be by using worker object model, that was shown in Qt examples and explained a few times on QT-related blogs:
class Worker : public QObject
{
Q_OBJECT
private slots:
void onTimeout()
{
qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();
}
};
class Thread : public QThread
{
Q_OBJECT
private:
void run()
{
qDebug()<<"From work thread: "<<currentThreadId();
QTimer timer;
Worker worker;
connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));
timer.start(1000);
exec();
}
};
worker constructed inside run() is "property" of the thread it created, so figuratively speaking, it is slaved to its context. The same effect maybe achieved if you create worker in other thread, then move it to this thread before connection was made. When you connect signal to slot of the QThread itself, you connect child thread to thread it was created by.
Use of
connect(&timer, SIGNAL(timeout()), this, SLOT(onTimeout()), Qt::DirectConnection);
or creating connection from your thread sometimes seems to achieve proper result, but not in this case, where you try use objects constructed in different threads together. Calling moveToThread(this) in constructor is a thing not recommended to do.

Read a file in background to update Qjsonvalue

I need to update the content of a field on my QWidget via a JSON file (updated in real time). I've read about functions readLine() and readAll() of QFile, but when I try a loop like :
while(true):
jsfile.readLine()
creation of objects, update of values, display etc ...
I lost the focus on my window. But I want to keep the control of the application with my buttons and obviously to watch the evolution of the JSON values.
I have thought that Qt manages itself the events and keeps the focus on the current window, but like I've said, it's not the case.
Is there a good solution (multi threads maybe) to use my window while the application reads the file (with new informations in real time)?
(With the constraint "real time" I can't read the whole file every time and I've no choice about the format of this file)
Update
I tried the thread method.
So, I choose to create my thread instance into the main (with my main window) and connect here. But, when I run the program, I've this error :
no matching member function for call to 'connect'
Reader reader;
QObject::connect(controler, SIGNAL(ready()),
reader, SLOT(received()));
According to this error, I've thought that the reason was main don't inherits of Object, and so, I've move the connection ans the creation of thread instance into my main window.
Reader reader;
QObject::connect(reader, SIGNAL(newobject(QJsonObject)),
this, SLOT(displayJSON(QJsonObject)));
With this one, I've the same error while I've already connect lot of widget into this class without any error.
What can be the problem ?
Update 2
I've a solution when I give as argument my main window (controler) in reader's constructor and connect into this one but, if possible, I would an explanation for the previous problem.
The current problem that I have is that signals are emit well but slots are executed after the end the application (so after the end of the thread's execution and not during)
This isn't really the subject of this topic so we can close this one.
You can use QThread (Qt documentation: QThread) class to create a thread, which will read your file. The main thread will execute your GUI application and it will be available during file reading.
You can find a simple example in documentation for creating your thread:
class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
workerThread->start();
}
You can modify this example for your purpose. For example, WorkerThread for your task may be something like this:
class WorkerThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
while(!stopFlag)
{
// read JSON file to QByteArray. Use QFile and QTextStream
// use QJsonDocument to read JSON content
// find what is new in JSON
emit signalSomethingNew(/*parameters*/);
QThread::currentThread()->msleep(/*timeout*/);
}
}
signals:
void signalSomethingNew(/*parameters*/);
};
At the end you must implement slot on your QWidget for signalSomethingNew(/*parameters*/) and make connection:
connect(yourThread, &WorkingThread::signalSomethingNew, youWidget, &YouWidget::yourSlot);
For working with JSON data: QJsonDocument
I'm interpreting your question as "my application is unresponsive whilst doing work" rather than "my focus jumped to another window" - please comment if you meant something different.
You have a choice of options:
Create and run a background QThread to do the work. Have it emit signals (connected to your widgets using Qt::QueuedConnection - the default) when it has results to display.
This is a good solution when the worker has a lot of computation to do, or needs all the input to be read before it can start. It works very well when the target system has processors available with no other work to do.
Use a QSocketNotifier to signal your GUI thread when some of the input becomes available (note that the name is misleading - it actually works on all kinds of file descriptor, not just sockets).
This is appropriate when the algorithm is simple and incremental - i.e. if a small chunk of input can be read and processed quickly.
Incorporate periodic calls to processEvents() in your algorithm:
auto *const dispatcher = QThread::currentThread()->eventDispatcher;
while (line = json.readLine()) {
doSomethingWith(line);
if (dispatcher)
dispatcher->processEvents();
}
This won't work unless you can modify the algorithm like this - if the loop is in somebody else's (closed) code, then you'll need one of the other solutions.

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
}

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.