This is part of the main.
This code create a worker and a workerthread.
The worker is moved to the workerthread.
The worker is then waiting for the signal to ask it to work.
The worker emit a signal with result when job done.
The main supposed to catch that signal and initialize a variable in the main.
main()
{.........
// This is the variable to be changed
variableToGetFromWorker = 0;
qDebug() << "Main thread: " << QThread::currentThreadId();
QThread workerThread;
worker* stupidTom = new stupidTom(number);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob()));
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int)));
workerThread.start();
workerThread.wait();
...........}
// This is a slot at main. Suppose to catch the signal from the worker
void main::jobDone(int result)
{
qDebug() << "Changing variable";
variableToGetFromWorker = result;
}
This is the doJob slot of the worker.
void worker::doJob()
{
qDebug() << "worker::doJob invoked.";
qDebug() << "worker Thread:" << QThread::currentThreadId();
// Doing Job here
emit jobDone(result);
}
It is the qDebug result
Main thread: 0x7ffff7fc6780
worker::doJob invoked.
worker Thread: 0x7fffdab44700
In Debug mode, I find that the program is stop at workerThread.wait()
and never go to main::jobDone(int result). What is the reason?
Little editing on the main code:
QThread workerThread;
worker* stupidTom = new stupidTom(number);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, &workerThread, &QObject::deleteLater);
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob()));
connect(stupidTom, SIGNAL(jobDone(int)), this, SLOT(jobDone(int)));
connect(stupidTom, SIGNAL(jobDone(int)), &workerThread, SLOT(quit()));
workerThread.start();
workerThread.wait();
As long as signals supposed to invoke slots. That won't be working on wait() on the main thread that supposed to run the slot or specifically jobDone signal.
Make sure to understand the difference between QThread::exec() and QThread::wait() in your application. Normally in the real app your thread would be looping (running) while the thread that launched it is still looping as well. The loop is implemented in protected QThread::exec() method. We usually don't need to call exec() explicitly but we need to allow the thread to run. You can do that by making main function to use QEventLoop for looping:
int main()
{
//...
workerThread.start();
QEventLoop eventLoop;
// here you will probably want to hook-up QEventLoop::quit() slot
// to eventually quit the process
int returnCode = eventLoop.exec();
//...
return returnCode;
}
And this is also wrong:
connect(&workerThread, SIGNAL(start()), stupidTom, SLOT(doJob()));
Instead you should create your own job object and do QObject::moveToThread for it. Here is a nice article about it. So it should rather look like:
connect(&workerThread, SIGNAL(started()), stupidTom, SLOT(doJob()));
I likely understand why you attempted to run the thread that way as above. It is similar to many C++ examples. You can also do that in Qt but you also need to realize how exactly you'll be waiting on completion of workerThread. And Qt most popular way to do the interaction between threads is with signals and slots. That is why we should use QEventLoop in main. But of course there is an alternative. For lower level plain C++ you can use mutex and condition variable to accomplish the same. Or that same wait() but then there is no signals involved.
Also watch the debug output, whether or not all the connect statements really connect proper signals to slots. In case if there is no connect it prints the warning.
Related
I've have a worker class that do image acquisition in the background.
void acq::run ()
{
while (m_started)
{
blocking_call();
}
emit workFinished();
}
void acq::start ()
{
m_started = true;
run();
}
void acq::stop ()
{
m_started = false;
}
start (); stop () are slots and workFinished is a signal.
So in my UI Class, I launch the worker and I connect the signals to the slots :
m_thread = new QThread;
m_worker = new acq();
m_worker->moveToThread(m_thread);
// When the thread starts, then start the acquisition.
connect(m_thread, SIGNAL (started ()), m_worker, SLOT (start ()));
// When the worker has finished, then close the thread
connect(m_worker, SIGNAL(workFinished()), m_thread, SLOT(quit()));
m_thread->start();
At this point, I implemented the slot, closeEvent
void UIClass::closeEvent (QCloseEvent *event)
{
m_worker->stop(); // tell the worker to close
m_thread->wait(); // wait until the m_thread.quit() function is called
event->accept(); // quit the window
}
Unfortanely, m_thread->wait() is blocking. Even if the signal quit() is emmited
Thanks
edit:
I added these two connections :
connect(m_worker, SIGNAL(workFinished()), m_worker, SLOT(deleteLater()));
connect(m_thread, SIGNAL(finished()), m_thread, SLOT(deleteLater()));
and a Qdebug into acq::~acq()
The message is printed that prove, that stop is called, workFinished is emitted, deleteLater() is emitted.
A normal signal/slot connection between objects on different threads requires that the thread of the receiver object runs an event loop.
Your receiver thread does theoretically run its event loop, but the event loop is busy executing the start() slot because run() never returns.
You either need to unblock the receiver event loop or call the stop slot with a Qt::DirectConnection.
When doing the latter you need to be aware that the slot is now called in the context of the sender thread and you need to protect m_started against concurrent access.
Alternatively to using your own flag you could use QThread::requestInterruption() and QThread::isInterruptionRequested()
Add
QCoreApplication::processEvents();
to your loop and it'll work.
The reason you deadlock is that the call to acq::run() blocks and does not leave time for acq::stop() to be executed on the worker thread.
With the help of Ralph Tandetzky and Kevin Krammer I finally found a solution.
Instead of closing the thread with m_worker->stop();, I use QMetaObject::invokeMethod(m_worker, "stop", Qt::ConnectionType::QueuedConnection); and QCoreApplication::processEvents(); in the worker event loop. The behavior does not change, but I hope it will prevent race condition or other problems.
Instead of using : connect(m_worker, SIGNAL(workFinished()), m_thread, SLOT(quit()));, I use a custom slot :
connect(m_worker, &Acq::workFinished, [=]
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection);
});
We use DirectConnection because we are outside the infinite loop, so the event are not processed.
With that, I had a last problem. m_thread->wait is blocking, and I've to read events, otherwise, my custom slot will never be called. So added an event loop to my UI Class QEventLoop m_loop.
Just before m_thread->wait(), I wrote m_loop.exec();
And finally, In my custom slot, I put m_loop.quit()
connect(m_worker, &Acq::workFinished, [=]
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection);
m_loop.quit();
});
m_loop.exec() process event until quit m_loop.quit() is called. With that method, I don't even need m_thread->wait() because m_loop.quit() is called when workFinished is emitted. I don't need QMetaObject::invokeMethod(m_thread, "quit", Qt::ConnectionType::DirectConnection); anymore
Now it works like a charm
EDIT: This solution is very heavy and ugly, Qt (https://www.qtdeveloperdays.com/sites/default/files/David%20Johnson%20qthreads.pdf) sugest to use subclass and requestInteruption in my case.
Consider MyThread that derives from QThread and implements it's run() routine like this
void MyThread::run() {
QThread::exec();
}
or equivalently
void MyThread::run() {
QEventLoop eventLoop(this);
eventLoop.exec();
}
In this state how does one cause the 'exec' to return by some action in another thread?
To consider the opposite case: without polling, how might one post an event from the thread back to the main thread?
Apparently signals that are emitted from a thread are handled in the same thread.
You seem to have some misunderstanding how QThreads are supposed to work. Unfortunately, you are not alone with this.
The first thing to do is to read about the correct usage in here:
How To Really, Truly Use QThreads; The Full Explanation
So, what you should write is something like this:
QThread* thread1 = new QThread;
QThread* thread2 = new QThread;
Task1* task1 = new Task1();
task1->moveToThread(thread1);
Task2* task2 = new Task2();
task2->moveToThread(thread2);
connect(task2, SIGNAL(finished()), thread1, SLOT(quit()));
connect(thread2, SIGNAL(started()), task2, SLOT(process()));
thread1->start();
thread2->start();
As you can see, I am using the quit() slot just like the aforementioned example. You will need to use then emit finished() in your task2 which tries to terminate thread1 or vice versa.
QEventLoop has a slot quit that you can call. If you put a reference to the eventloop in your mythread, you can then use that to call the slot.
Signals/slots can be used in a cross thread fashion. More information here: Signals and Slots Across Threads
QMetaObject::invokeMethod( eventloop, "quit", Qt::QueuedConnection)
I got some trouble with Qt Threads and Connections. I found several tutorials and discussions on this topic, I followed this tutorial to create the thread. But I still got the problem, that calling wait() on the thread never returns and the UI freezes.
A similar question was asked here before (the second example):
Qt connection type between threads: why does this work?
In the last edit of the question, the author mentions that he had created a deadlock. I assume, I do the same in my application. But I still do not understand, why this happens. Reading the suggested article did not help me understanding. I just got the point, that deadlocks can happen, but I don't know, what's causing it there or in my case.
I have also created an example that's reduced to the core problem. Find the code at the bottom of this question.
So my questions are:
What exactly is the cause for the deadlock in my example?
Is there a solution without making the connection a direct connection?
I'd really appreciate any hints.
Thanks!
EDIT:
Because of the comments I tried it to send the stop request via a signal and I added a QCoreApplication::processEvents() call in the thread loop. But the main problem is still the same.
EDIT2:
I found an acceptable solution, after thinking a bit more about event loops:
thread.requestStop();
// now instead of using wait(), we poll and keep the event loop alive
// polling is not nice, but if it does not take a very long time
// for the thread to finish, it is acceptable for me.
while (thread.isRunning())
{
// This ensures that the finished() signal
// will be processed by the thread object
QCoreApplication::processEvents();
}
This actually works and the worker itself controls how to stop working.
After coming up with this, I also have an explanation for the freezing issue: Calling wait seems to keep the main thread either busy or suspended so it does not process any events. Since the thread object lives in the main thread, the thread's finished() signal is enqued but never processed.
My implicit assumption, that thread.wait() would still keep the event loop working, was obviously wrong. But then, what's the QThread::wait() function good for?!?
This is just a theory, but maybe someone here can verify or falsify it...
EDIT 3 (final solution):
After reading this small article and implmenting a subclassing solution, I think that this is preferable for this particular proble. There is no need for an event loop and I'm fine with direct calls on a different thread and using mutex protection. It's less code, easier to understand and easier to debug.
I think I would use the non-subclassing strategy only, if there were more interaction with the thread than just start and pause.
My reduced Example
Maybe I should point out, that I do not delete the thread, because in my original application, I want to resume later, so stopping it actually means pausing it.
worker.h:
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QMutex>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject* parent = NULL);
public slots:
void doWork();
void requestStop();
signals:
void finished();
private:
bool stopRequested;
QMutex mutex;
};
#endif // WORKER_H
worker.cpp:
#include "worker.h"
#include <QThread>
#include <iostream>
using namespace std;
Worker::Worker(QObject *parent)
: stopRequested(false)
{
}
void Worker::doWork()
{
static int cnt = 0;
// local loop control variable
// to make the usage of the mutex easier.
bool stopRequesteLocal = false;
while (!stopRequesteLocal)
{
cout << ++cnt << endl;
QThread::msleep(100);
mutex.lock();
stopRequesteLocal = stopRequested;
mutex.unlock();
}
cout << "Finishing soon..." << endl;
QThread::sleep(2);
emit finished();
}
void Worker::requestStop()
{
mutex.lock();
stopRequested = true;
mutex.unlock();
}
main program:
#include <QCoreApplication>
#include <QThread>
#include <QtCore>
#include <iostream>
#include "worker.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread thread;
Worker worker;
QObject::connect(&thread, SIGNAL(started()), &worker, SLOT(doWork()));
// this does not work:
QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()));
// this would work:
//QObject::connect(&worker, SIGNAL(finished()), &thread, SLOT(quit()), Qt::DirectConnection);
// relocating the moveToThread call does not change anything.
worker.moveToThread(&thread);
thread.start();
QThread::sleep(2);
worker.requestStop();
cout << "Stop requested, wait for thread." << endl;
thread.wait();
cout << "Thread finished" << endl;
// I do not know if this is correct, but it does not really matter, because
// the program never gets here.
QCoreApplication::exit(0);
}
I added my own answere to the question text as EDIT 3.
The first issue I see is that you're not using signals and slots to communicate between the objects running on different threads; main and the new thread that hosts the worker object.
You move the worker object to the second thread, but call a function on the worker object from the main thread: -
thread.start();
QThread::sleep(2);
worker.requestStop(); // Aaahh, this is running on the new thread!!!
Considering that a thread has its own stack and registers I really don't see how this is safe.
If you use signals and slots, Qt handles a lot of threading issues. While you should be able to use a variable to control the 2nd thread, it would also be cleaner to use signals and slots.
Note that when a signal is emitted from one thread, a message is posted to the thread of the receiving object, if the sender and receiver are on separate threads.
Convert your code to use signals and slots for communicating between objects on different threads and your deadlock should disappear.
It doesn't look like you have read that article completely.
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();
You have only implemented partially of what is suggested on the article.
QThread::wait() will wait until QThread::finished() is emitted from doWork(). Please emit this SIGNAL if you need to quit from this thread and return to the main thread. For this you need to keep a reference of the thread on which this object is moved to.
In the example below (inside Qt GUI application) a new thread is started (with an event loop in which I want some work to be done):
void doWork()
{
QThread* workerThread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(workerThread);
connect(workerThread, SIGNAL(started()), worker, SLOT(startWork()));
connect(worker, SIGNAL(finished()), workerThread, SLOT(quit()));
connect(workerThread, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
workerThread->start();
}
startWork() can be a long running operation during which the application can be closed.
I expected that the application will not be closed as long as startWork() is being executed on the workerThread. It seems though, that when I close the last application window, the workerThread is gone instantaneously (during long running operation) and application closes without problems.
The questions arose:
Why was the workerThread wiped right away?
Is it some parent/child issue?
How Qt handles such situation?
Is it programmer mistake, not to call wait() on QThread (eventually)?
Even if so, I tried to wait() inside a slot for aboutToQuit() and application wasn't closed after long running operation was done (with setup as above). Only quit(); wait(); (inside the slot mentioned) allowed the application to close. Why?
QThread has, basically, a long-standing API bug: it isn't always in a destructible state. In C++, an object is considered to be in destructible state when it's safe to invoke its destructor. Destructing a running QThread is an error. A QThread is merely a thread controller, it's not the "thread" itself. Think of how QFile acts: you can destruct it at any time, whether it's open or not. It truly encapsulates the notion of a file as a resource. A QThread is too thin of a wrapper around the native (system) thread: when you destruct it, it does not terminate nor dispose of the native thread if there is one. This is a resource leak (threads are OS resources), and people trip over this issue over and over again.
When the application's main() function returns, your implementation of the C/C++ runtime library happens to terminate all of the application's threads, effectively terminating the entirety of the application. Whether this is the behavior you desire is up to you. You're supposed to quit() and wait() your event-loop-running thread. For threads without an event loop, quit() is a no-op and you must implement your own quit flag. You must wait() on the thread before you destruct it. This is to prevent race conditions.
Below is a safe wrapper for QThread. It is a final class, since you can't reimplement run. This is important, since a reimplementation of run could be done in such a way that makes quit a no-op, breaking the contract of the class.
#include <QThread>
#include <QPointer>
class Thread : public QThread {
using QThread::run; // final
public:
Thread(QObject * parent = 0) : QThread(parent) {}
~Thread() { quit(); wait(); }
};
class ThreadQuitter {
public:
typedef QList<QPointer<Thread>> List;
private:
List m_threads;
Q_DISABLE_COPY(ThreadQuitter)
public:
ThreadQuitter() {}
ThreadQuitter(const List & threads) : m_threads(threads) {}
ThreadQuitter(List && threads) : m_threads(std::move(threads)) {}
ThreadQuitter & operator<<(Thread* thread) {
m_threads << thread; return *this;
}
ThreadQuitter & operator<<(Thread& thread) {
m_threads << &thread; return *this;
}
~ThreadQuitter() {
foreach(Thread* thread, m_threads) thread->quit();
}
};
It could be used as follows:
#include <QCoreApplication>
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
QObject worker1, worker2;
Thread thread1, thread2;
// Style 1
ThreadQuitter quitter;
quitter << thread1 << thread2;
// Style 2
ThreadQuitter quitterB(ThreadQuitter::List() << &thread1 << &thread2);
//
worker1.moveToThread(&thread1);
worker2.moveToThread(&thread2);
thread1.start();
thread2.start();
QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
return app.exec();
}
Upon return from main, the thread quitter will quit() all worker threads. This allows the threads to wind down in parallel. Then, thread2.~Thread will wait for that thread to finish, then thread1.~Thread will do the same. The threads are now gone, the objects are threadless and can be safely destructed: worker2.~QObject is invoked first, followed by worker1.~QObject.
1) Is it parent / child issue?
Not in the case of your code - You're not parenting the QThread. Qt doesn't like you to just terminate the main thread if you've other threads running. You're likely to see it complain in the standard output that the other thread was still running when the application was terminated. However, Qt will kill the other thread, which is why there's a function to call and wait for the thread to terminate properly.
2) Is it programmer mistake not to call wait()?
Yes. If you're having issues with the Thread not quitting properly, it's because you're not handling it correctly, in which case you could open another question and show the code as to how you're handling the wait before quitting.
when I close the last application window, the workerThread is gone instantaneously
Note that there's a function in QApplication called setQuitOnLastWindowClosed, which you can set to false, to prevent the app automatically quitting on closing the last window.
I'm trying to create a program using threads:
the main start with a loop.
When a test returns true, I create an object and I want that object to work in an other thread
then return and start the test .
QCoreApplication a(argc, argv);
while(true){
Cmd cmd;
cmd =db->select(cmd);
if(cmd.isNull()){
sleep(2);
continue ;
}
QThread *thread = new QThread( );
process *class= new process ();
class->moveToThread(thread);
thread->start();
qDebug() << " msg"; // this doesn't run until class finish it's work
}
return a.exec();
the problem is when i start the new thread the main thread stops and wait for the new thread's finish .
The canonical Qt way would look like this:
QThread* thread = new QThread( );
Task* task = new Task();
// move the task object to the thread BEFORE connecting any signal/slots
task->moveToThread(thread);
connect(thread, SIGNAL(started()), task, SLOT(doWork()));
connect(task, SIGNAL(workFinished()), thread, SLOT(quit()));
// automatically delete thread and task object when work is done:
connect(task, SIGNAL(workFinished()), task, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
in case you arent familiar with signals/slots, the Task class would look something like this:
class Task : public QObject
{
Q_OBJECT
public:
Task();
~Task();
public slots:
// doWork must emit workFinished when it is done.
void doWork();
signals:
void workFinished();
};
I don't know how you structured your process class, but this is not really the way that moveToThread works. The moveToThread function tells QT that any slots need to be executed in the new thread rather than in the thread they were signaled from. (edit: Actually, I now remember it defaults to the tread the object was created in)
Also, if you do the work in your process class from the constructor it will not run in the new thread either.
The simplest way to have your process class execute in a new thread is to derive it from QThread and override the run method. Then you never need to call move to thread at all.