I have a problem with signal/slots in a QThread class. My design looks like this:
class Manager : public QObject {
Q_OBJECT
public:
Manager(QObject* parent) : QObject(parent) {
Thread thread* = new Thread(this);
connect(this, SIGNAL(testsignal()), thread, SLOT(test()));
thread->start();
...
emit testsignal();
}
signals:
void testsignal();
};
class Thread : public QThread {
Q_OBJECT
public slots:
void test() {
qDebug() << "TEST";
}
private:
void run() {}
};
The signal never reaches my test() method. Can someone help? Thanks.
The problem is that sending signals across threads results in queuing the signal into the target thread's event queue (a queued connection). If that thread never processes events, it'll never get the signal.
Also, according to the QThread::run documentation:
Returning from this method will end the execution of the thread.
In other words, having an empty run method results in instant termination of the thread, so you're sending a signal to a dead thread.
Signals sent to a QThread object will go to the thread of the parent object. In this case to the same thread that created it.
To have a object live on another thread you should move it to that thread:
class Manager : public QObject {
Q_OBJECT
public:
Manager(QObject* parent) : QObject(parent) {
Thread thread* = new QThread(this);
Receiver* rec = new Receiver(); //no parent
connect(this, SIGNAL(testsignal()), rec, SLOT(test()));
connect(thread, SIGNAL(finished()), rec, SLOT(deleteLater()));
rec->moveToThread(thread);
thread->start();
...
emit testsignal();
}
signals:
void testsignal();
};
class Receiver: public QObject {
Q_OBJECT
public slots:
void test() {
qDebug() << "TEST";
}
};
Related
QThread documentation suggests two ways to make code run in a separate thread. If I use moveToThread approach, I have to call processEvents() to issue the timeouts, to have the lambda executed. And this seems to cost a lot of CPU. Why is so?
class Worker : public QObject
{
Q_OBJECT
QTimer* timer;
bool m_abort = false;
public:
Worker() {}
void abort() {m_abort = true;}
public slots:
void run() {
timer = new QTimer;
connect(timer, &QTimer::timeout, []{qDebug() << "computed";});
timer->start(1000);
forever {
if (m_abort) break;
QCoreApplication::processEvents();
}
}
};
class MainWidget : public QWidget
{
Q_OBJECT
QThread thread;
Worker* worker;
public:
MainWidget()
{
worker = new Worker;
worker->moveToThread(&thread);
connect(this, &MainWidget::start, worker, &Worker::run);
thread.start();
emit start();
}
~MainWidget(){worker->abort(); thread.quit(); thread.wait();}
signals:
void start();
};
However if I subclass QThread and reimplement run() it's not necessary to call processEvents. And CPU cost seems lower. Why?
class Worker : public QThread
{
public:
Worker() {}
protected:
void run() override {
QTimer timer;
connect(&timer, &QTimer::timeout, []{qDebug() << "computed";});
timer.start(1000);
exec();
}
};
class MainWidget : public QWidget
{
Q_OBJECT
Worker* worker;
public:
MainWidget()
{
worker = new Worker;
worker->start();
}
};
your run() function 'blocks' the thread. It is being invoked in the thread context, but never returns. This means, the event loop in the thread doesn't get executed anymore as soon as your run() funtion is called.
For the timer events to call your lambdas, the event loop has to be processed.
If you would modify your run function like this:
void run() {
timer = new QTimer(this);
connect(timer, &QTimer::timeout, []{qDebug() << "computed";});
timer->start(1000);
// don't loop here, instead exit the function
// and let the thread return back to the event loop
}
then your lambdas should get called. The thread will also keep running until you call thread.quit()
note: you can also connect directly to the '''started''' signal of the thread:
connect(&thread, &QThread::started, worker, &Worker::run);
thread.start();
moveToThread approach might be improved by calling run() function just after thread emit started.
But I still don't know why the way I put it initially doesn't work.
Currently I have two classes that look something like this:
class Worker : public QObject
{
Q_OBJECT
bool aborted = false;
public:
Worker() : QObject() {}
public slots:
void abort() { aborted = true; }
void doWork()
{
while(!aborted && !work_finished)
{
//do work
QCoreApplication::processEvents();
}
}
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() : QObject()
{
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &Worker::deleteLater);
connect(this, &Controller::startWork, worker, &Worker::doWork);
connect(this, &Controller::aborted, worker, &Worker::abort);
}
signals:
void startWork();
void aborted();
};
Controller *cont = new Controller;
emit cont->startWork(); // Start the loop
emit cont->aborted(); // Stop the loop
So the idea is that there is a loop running in a Worker thread, which can be stopped from a Controller thread.
In the example this is done by calling QCoreApplication::processEvents(), which allows signals to call slots before returning control to the loop.
It's important the loop is only stopped at the start or end of an iteration.
Although this works nicely, I think QCoreApplication::processEvents() is pretty expensive, at least when used inside a very long loop (up to thousands in practice).
So my question is, how can I achieve the same result in a better/cheaper way?
There are three alternative solutions that I'm aware of at this time.
1. QThread::requestInterruption (suggested by #Felix)
According to QThread::isInterruptionRequested:
Take care not to call it too often, to keep the overhead low.
Whereas QCoreApplication::processEvents makes no remark on performance or memory usage, so I don't think QThread::requestInterruption is an improvement over QCoreApplication::processEvents in this case.
2. std::atomic (suggested by #Felix)
The main characteristic of atomic objects is that access to this contained value from different threads cannot cause data races [...]
The boolean can be stored inside a std::atomic which can be made a member of the Controller class instead of the Worker class. Then we need to pass a reference to aborted to and store it in Worker, and set it to true from Controller when needed.
I didn't fully test this approach, so please correct me if I got something wrong.
class Worker : public QObject {
Q_OBJECT
std::atomic<bool> &aborted;
public:
Worker(std::atomic<bool> &aborted) : QObject(), aborted(aborted) {}
public slots:
void doWork() {
while(!aborted.load() && !work_finished) /* do work */
}
};
class Controller : public QObject {
Q_OBJECT
QThread workerThread;
std::atomic<bool> aborted;
public:
Controller() : QObject() {
aborted.store(false);
Worker *worker = new Worker(aborted);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &Worker::deleteLater);
connect(this, &Controller::startWork, worker, &Worker::doWork);
connect(this, &Controller::aborted, worker, &Worker::abort);
}
void abort() { aborted.store(true); }
signals:
void startWork();
};
Controller *cont = new Controller;
emit cont->startWork(); // Start the loop
cont->abort(); // Stop the loop
3. QWaitCondition & QMutex
A boolean paused will be needed. Controller and Worker need read/write access to it.
Set paused to true in Controller when needed.
During the loop in Worker, if(paused): QWaitCondition::wait() until QWaitCondition::wakeAll() is called from the calling thread.
QMutex::lock will need to be called whenever paused is accessed.
class Worker : public QObject {
Q_OBJECT
bool &aborted, &paused;
QWaitCondition &waitCond;
QMutex &mutex;
public:
Worker(bool &aborted, bool &paused, QWaitCondition &waitCond, QQMutex &mutex)
: QObject(), aborted(aborted), paused(paused), waitCond(waitCond), mutex(mutex) {}
public slots:
void doWork() {
while(!aborted && !work_finished) {
//do work
mutex.lock();
if(paused) {
waitCond.wait(&mutex);
paused = false;
}
mutex.unlock();
}
}
void abort() { aborted = true; }
};
class Controller : public QObject {
Q_OBJECT
bool aborted=false, paused=false;
QWaitCondition waitCond;
QMutex mutex;
QThread workerThread;
public:
Controller() : QObject() {
Worker *worker = new Worker(aborted, paused, waitCond, mutex);
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &Worker::deleteLater);
connect(this, &Controller::startWork, worker, &Worker::doWork);
}
void abort() {
mutex.lock();
paused = true; // Worker starts waiting
mutex.unlock();
if(confirmed_by_user) aborted = true; // Don't need to lock because Worker is waiting
waitCond.wakeAll(); // Worker resumes loop
}
signals:
void startWork();
};
Controller *cont = new Controller();
emit cont->startWork(); // Start the loop
cont->abort(); // Stop the loop
I have a C++ class. It inherits a parent class which inherits QQuickItem. Therefore now I can't inherit from QThread since the QQuickItem is already there.
(Error if tried: Object is an ambiguous base of 'xClass')
My class has been registered by qmlRegisterType and I can access its methods through QML.
There is a piece of code which runs when a button is pressed from QML. This piece of code takes a lot of time to execute and it steals the focus from QML window totally.
How to write a piece of code in my C++ class which when I run doesn't steal all the focus to itself?
One way to move a blocking process to a new thread is to create a worker object by subclassing QObject. Then use signals and slots to signal when the thread should process some data and to return the data.
Here is an example from Qt docs:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
You can find more threading technologies here. Check them all out and decide which one suits your needs the best.
I know how to wait for a single object to finish, using
QEventLoop eventLoop;
connect(&obj, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec();
But now I have several objects which I want to 'run' in parallel, so I need to wait until all of them have sent their finished() SIGNALs.
This would be like a signals-and-slots version of the WaitForMultipleObjects WinApi function.
How should I go about doing that?
I would connect the finished signal to a class that counts the # of signals received and emits quit() when it hits the expected count.
Something like this:
class EmitIfCountReached : public QObject
{
Q_OBJECT
public:
EmitIfCountReached( int expectedCount, QObject* parent = nullptr) : m_expected(expectedCount), m_count(0), QObject(parent) {}
signals:
void finished();
protected slots:
void increment() {
m_count++;
if (m_count >= m_expected) {
emit finished();
}
}
protected:
int m_count;
int m_expected;
};
I am using Qt in order to write a GUI application.
A main thread is responsible for the GUI and creates an QThread in order to do some work with an object.
class Worker
{
void start() {
QTimer* timer = new Timer();
connect(timer,SIGNAL(timeout()),this,SLOT(do()));
}
void do() {
//do some stuff
emit finished();
}
}
class GUI
{
//do some GUI work then call startWorker();
void startWorker() {
QThread* thread = new Thread();
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(thread, SIGNAL(started()), worker, SLOT(start()));
connect(worker, SIGNAL(finished()), workerthread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
}
}
Now I have several problems:
The timer in my worker class does not work. Maybe it is because the new thread has no event loop, but I have no idea how to create such one. I tried
connect(workerthread, SIGNAL(started()), workerthread, SLOT(exec()));
but it does not work either.
When I try to wait on the new thread, the signal is never sent
class GUI
{
void exit() {
thread->wait();
}
}
I think it also is because there is no event loop and because of that no signal is emitted.
Does anybody have an idea how to solve these problems?
why not use qthreadpool, than you make your task class inherits from qrunnable and qobject, this way you can use signals and slots to pass data from one thread to another, is much simpler to implement, and increase performance from not recreating a thread or having one sleeping all the time
class myTask : public QObject, public QRunnable{
Q_OBJECT
protected:
void run(); //where you actually implement what is supposed to do
signals:
void done(int data);//change int to whatever data type you need
}
//moc click example, or use a timer to call this function every x amount of time
void button_click(){
myTask *task = new myTask();
task->setAutoDelete(true);
connect(task,SIGNAL(done(int)),this,SLOT(after_done(int)),Qt::QueuedConnection);
QThreadPool::globalInstance()->start(task);
}
by default you application gets 1 thread automatically, which you can use to handle the graphic, than use the qthreadpool to process the data/object on demand, you can even set the max amount of threads your application can use to process new request, the others will stay in a queue until one thread is freed
QThreadPool::globalInstance()->setMaxThreadCount(5);
this is a sample code for you :
QThread* thread = new QThread();
Worker* worker = new Worker(3000);
worker->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), worker, SLOT(start()));
thread->start();`
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(qint32,QObject *parent = 0);
qint32 myTime;
signals:
void workFinished();
public slots:
void doWork();
void start();
private:
QTimer *timer;
};
#include "worker.h"
#include <QTimer>
#include <QDebug>
Worker::Worker(qint32 t,QObject *parent) :
QObject(parent)
{
myTime=t;
}
void Worker::start()
{
timer = new QTimer();
timer->start(myTime);
qDebug()<<QString("start work in time:%1").arg(myTime);
connect(timer,SIGNAL(timeout()),this,SLOT(doWork()));
}
void Worker::doWork()
{
qDebug()<<"dowork";
timer->stop();
emit workFinished();
}
Debug results :
start work in time:3000
I hope this helps you.