creating new thread using Qthread-Qt5 - c++

I am trying to create a new thread gpsthread which should run in the back ground, and store the value.
class gpsthread: public QThread{
Q_OBJECT
private:nrega_status_t status2;
public:
explicit gpsthread(QObject *parent = 0):QThread(parent) {
// QTimer *t = new QTimer(this);
// connect(t, SIGNAL(timeout()), this, SLOT(processgps()));
// t->start(10000);
}
void run(){
qDebug()<<"inside gps thread\n";
QTimer *t = new QTimer(this);
connect(t, SIGNAL(timeout()), this, SLOT(processgps()));
t->start(10000);
}
public slots:void processgps(){
int status2;
status2=gps_management();
}
};
My main class is quickview.
int main(int argc, char *argv[])
{
QString file = "qml/main.qml";
QApplication app(argc, argv);
TranslationTest myObj;
QuickView view;
subthread object;
gpsthread obj;
gprsthread gprs;
view.rootContext()->setContextProperty("rootItem", (QObject *)&myObj);
obj.start();
//from subthread
QObject::connect(&object, SIGNAL(batterytoqml(QVariant,QVariant)),item, SLOT(frombattery(QVariant,QVariant)));
QObject::connect(&gprs, SIGNAL(gprstoqml(QVariant)),item, SLOT(fromgprs(QVariant)));
return app.exec();
}
I have tried this as well
class gpsthread: public QThread{
Q_OBJECT
private:nrega_status_t status2;
public:QTimer* t;
explicit gpsthread(QObject *parent = 0):QThread(parent) {
// QTimer *t = new QTimer(this);
// connect(t, SIGNAL(timeout()), this, SLOT(processgps()));
// t->start(10000);
}
void run(){
qDebug()<<"inside gps thread\n";
t = new QTimer(this);
connect(t, SIGNAL(timeout()), this, SLOT(processgps()));
t->start(10000);
exec();
}
public slots:void processgps(){
int status2;
status2=gps_management();
}
};
But it is giving error saying
QObject: Cannot create children for a parent that is in a different thread
If I create object in constructor then also it will give the same error because the object will be created in the main thread.
How to resolve this?

Inheriting from QThread is not the recommended usage. QThread is a complete class that runs an event loop, which is generally what you need. The documentation recommends using a worker object that inherits from QObject and does work in a slot. The worker is moved into a QThread. When a connected signal is sent, the slot will run in the correct thread.
class gpsworker: public QObject
{
Q_OBJECT
public:
explicit gpsworker(QObject *parent = 0):
QObject(parent)
{}
public slots:
void processgps() {
qDebug() << "processgps()" << QThread::currentThreadId();
}
}
void OwnerClass::startWorker() {
QTimer *timer = new QTimer(this);
QThread *thread = new QThread(this);
this->worker = new gpsworker();
this->worker->moveToThread(thread);
connect(timer, SIGNAL(timeout()), this->worker, SLOT(processgps()) );
connect(thread, SIGNAL(finished()), this->worker, SLOT(deleteLater()) );
thread->start();
timer->start();
}
If you want the timer to live in the other thread as well, QTimer::start is a slot.

QObject: Cannot create children for a parent that is in a different thready
is beacuse t = new QTimer(this) in the run() is creating an object in the child thread but this which point at gpsthread is in the main thread. A simple solution is t = new QTimer() without a parent and delete the timer in the destructor. Here is an example:
class gpsthread : public QThread {
Q_OBJECT
public:
explicit gpsthread(QObject *parent = 0):
QThread(parent)
,timer(NULL) {
qDebug() << "Parent thread" << QThread::currentThreadId();
}
~gpsthread() {
quit();
wait();
delete timer;
}
protected:
void run() {
qDebug() << "Inside gps thread" << QThread::currentThreadId();
timer = new QTimer; // no parent
connect(timer, SIGNAL(timeout()), this, SLOT(processgps()));
timer->start(1000);
exec();
}
public slots:
void processgps() {
qDebug() << "processgps()" << QThread::currentThreadId();
}
private:
QTimer *timer;
};
Soon you will find out console print:
Parent thread 0x3b28
inside gps thread 0x3f10
processgps() 0x3b28
processgps() 0x3b28
processgps() 0x3b28
processgps() 0x3b28
which means processgps() is not working in your child thread. This is because this slot is a member of gpsthread which is in the main thread. A simple solution is call processgps() directly and use sleep() as timer:
class gpsthread : public QThread
{
Q_OBJECT
public:
explicit gpsthread(QObject *parent = 0):
QThread(parent)
, abort(false) {
qDebug() << "Parent thread" << QThread::currentThreadId();
}
~gpsthread() {
abort = true;
wait();
}
protected:
void run() {
while(!abort) {
sleep(1);
processgps();
}
}
public slots:
void processgps() {
qDebug() << "processgps()" << QThread::currentThreadId();
}
private:
bool abort;
};
This is not a nice solution, a recommanded way is creating a worker to do all the job and then use QObject::moveToThread() as said in QThread Document

Related

How to read the response of a signal emitted from a different thread?

response print 0 instead of 999. What the proper way to read the response of the signal in this example?
class Worker : public QObject {
Q_OBJECT
public:
Worker()
{
connect(this, &Worker::signalTest, this, [this] (int x)
{
this->Test(x);
});
};
int Test(int x)
{
qDebug() << "x: " << x;
return 999;
}
public slots:
signals:
int signalTest(int x);
};
QThread* thread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(thread);
thread->start();
int response = emit worker->signalTest(10);
qDebug() << "response: " << response;
You need to read how to use signals slots correctly in Qt. You need to write a slot that accepts int response as input. And connect the signal to this slot with the QueuedConnection flag
Documentation: https://doc.qt.io/qt-6/signalsandslots.html
class Worker : public QObject {
Q_OBJECT
public:
Worker()
{
connect(this, &Worker::signalTest, this, [this] (int x)
{
this->Test(x);
});
};
int Test(int x)
{
qDebug() << "x: " << x;
emit signalResp(999);
}
public slots:
void slotResp(int x)
{
qDebug() << "responce" << x;
}
signals:
int signalTest(int x);
void signalResp(int x);
};
QThread* thread = new QThread();
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(signalResp(int), worker, SLOT(slotResp(int)), Qt::QueuedConnection);
thread->start();
emit worker->signalTest(10);

Is the timer being started from another thread?

QThread documentation suggests two ways to make code run in a separate thread. If I subclass QThread and reimplement run(), then I get
QBasicTimer::start: Timers cannot be started from another thread
-
#include <QWidget>
#include <QThread>
#include <QBasicTimer>
#include <QDebug>
#include <QEvent>
#include <QCoreApplication>
class Worker : public QThread
{
Q_OBJECT
int id;
bool m_abort = false;
bool compute = false;
public:
Worker() {}
protected:
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == id) {
compute = true;
} else {
QObject::timerEvent(event);
}
}
public slots:
void abort() {m_abort = true;}
void run() {
qDebug() << QThread::currentThreadId();
QBasicTimer timer;
id = timer.timerId();
timer.start(1000, this);
forever {
if (m_abort) break;
QCoreApplication::processEvents();
if (compute)
qDebug() << "computed";
compute = false;
}
}
};
class MainWidget : public QWidget
{
Q_OBJECT
QThread thread;
Worker* worker;
public:
MainWidget()
{
qDebug() << QThread::currentThreadId();
worker = new Worker;
worker->start();
}
~MainWidget(){worker->abort();}
};
1) Is the timer being started from another thread?
2) Why I don't get that warning when QBasicTimer is replaced by QTimer?
3) Why I don't get that warning when using moveToThread?
#include <QWidget>
#include <QThread>
#include <QBasicTimer>
#include <QDebug>
#include <QEvent>
#include <QCoreApplication>
class Worker : public QObject
{
Q_OBJECT
QBasicTimer* timer;
bool m_abort = false;
bool compute = false;
public:
Worker() {}
protected:
void timerEvent(QTimerEvent *event) override {
if (event->timerId() == timer->timerId()) {
compute = true;
} else {
QObject::timerEvent(event);
}
}
public slots:
void abort() {m_abort = true;}
void run() {
timer = new QBasicTimer;
timer->start(1000, this);
forever {
if (m_abort) break;
QCoreApplication::processEvents();
if (compute)
qDebug() << "computed";
compute = false;
}
}
};
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();
};
Regarding the first (non-moveToThread) example...
A quick look at the Qt source for QBasicTimer::start shows the following...
void QBasicTimer::start(int msec, QObject *obj)
{
QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
// ...
if (Q_UNLIKELY(obj && obj->thread() != eventDispatcher->thread())) {
qWarning("QBasicTimer::start: Timers cannot be started from another thread");
return;
}
So it expects its second argument obj to have a thread affinity equal to the current thread.
In your Worker::run implementation, however, you have...
timer.start(1000, this);
In this context the current thread is the new thread created by the QThread instance but this refers to the QWorker instance created by the MainWidget on the main GUI thread. Hence the warning.
Edit 1:
To the question...
why it works with moveToThread()?
Consider the implementation of the MainWidget ctor...
MainWidget()
{
worker = new Worker;
worker->moveToThread(&thread);
connect(this, &MainWidget::start, worker, &Worker::run);
thread.start();
emit start();
}
By the time Worker::run is called the Worker instance has been moved to the new thread. So when the line...
timer.start(1000, this);
executes, this (which refers to the Worker instance) is on the current thread and the thread affinity test in QBasicTimer::start passes without warning.
Sorry if the above is a bit convoluted but the important thing is to consider the thread affinity of the second arg to QBasicTimer::start: it must be the currently running thread.

Timer in thread's worker Qt

I'm trying to use timer in worker class. This is my Worker class:
Worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
signals:
void finished(void);
public slots:
void process(void);
void test(void);
private:
QMutex m_mutex;
};
Worker.cpp
void Worker::process(void)
{
qDebug() << "worker process"; //This works
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(test()));
forever
{
}
}
void Worker::test(void)
{
qDebug() << "test123"; //This does not work
}
I start this worker class in new thread:
QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
QObject::connect(thread, SIGNAL(started()), worker, SLOT(process()), Qt::QueuedConnection);
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
QObject::connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
thread->start();
The problem is that timer from Worker::process does not work. Do I need to initialize this timer in new thread in special way?
You need to call void QTimer::start(int msec) or void QTimer::start() after you create the timer. You also don't need "forever" in your process() slot.
Try this instead:
void Worker::process(void)
{
qDebug() << "worker process"; //This works
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(test()));
timer->start(1000); // Fire timer timeout each 1000ms.
}

Qt - Simple example using threads controlled by push buttons

I have been trying to get this simple example using threads activated by pushbuttons to work. It is based off of the solution in the question below:
How to implement frequent start/stop of a thread (QThread)
The main differences between the example solution above and my code below are:
I used a QWidget instead of MainWindow
I changed the name of signals for clarity
My code contains debugging information
I experimented with eliminating the signals created by worker as the didn't appear to do anything
It appears that the start/stop signals are not triggering their corresponding slots, but I am not experienced enough to troubleshoot why.
Additionally, I am unsure of the purpose of the signal:
SignalToObj_mainThreadGUI()
Is that just something that could be used and is not?
I have been trying to get this code to work for some time, so any help would be greatly appreciated.
main.cpp
#include "threadtest.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ThreadTest w;
w.show();
return a.exec();
}
threadtest.h
#include <QWidget>
#include <QThread>
#include "worker.h"
namespace Ui
{
class ThreadTest;
}
class ThreadTest : public QWidget
{
Q_OBJECT
public:
explicit ThreadTest(QWidget *parent = 0);
~ThreadTest();
signals:
void startWorkSignal();
void stopWorkSignal();
private slots:
void on_startButton_clicked();
void on_stopButton_clicked();
private:
Ui::ThreadTest *ui;
worker *myWorker;
QThread *WorkerThread;
};
threadtest.cpp
#include "threadtest.h"
#include "ui_threadtest.h"
ThreadTest::ThreadTest(QWidget *parent) :
QWidget(parent),
ui(new Ui::ThreadTest)
{
ui->setupUi(this);
myWorker = new worker;
WorkerThread = new QThread;
myWorker->moveToThread(WorkerThread);
connect(this,
SIGNAL(startWorkSignal()),
myWorker,
SLOT(StartWork())
);
connect(this,
SIGNAL(stopWorkSignal()),
myWorker,
SLOT(StopWork())
);
//Debug
this->dumpObjectInfo();
myWorker->dumpObjectInfo();
}
ThreadTest::~ThreadTest()
{
delete ui;
}
void ThreadTest::on_startButton_clicked()
{
qDebug() << "startwork signal emmitted";
emit startWorkSignal();
}
void ThreadTest::on_stopButton_clicked()
{
qDebug() << "stopwork signal emmitted";
emit stopWorkSignal();
}
worker.h
#include <QObject>
#include <QDebug>
class worker : public QObject {
Q_OBJECT
public:
explicit worker(QObject *parent = 0);
~worker();
signals:
void SignalToObj_mainThreadGUI();
//void running();
//void stopped();
public slots:
void StopWork();
void StartWork();
private slots:
void do_Work();
private:
volatile bool running, stopped;
};
worker.cpp
#include "worker.h"
worker::worker(QObject *parent) : QObject(parent), stopped(false),
running(false)
{
qDebug() << "running: " << running;
qDebug() << "stopped: " << stopped;
}
worker::~worker() {}
void worker::do_Work()
{
qDebug() << "inside do Work";
emit SignalToObj_mainThreadGUI();
if (!running || stopped) return;
// actual work here
/*
for (int i = 0; i < 100; i++)
{
qDebug() << "count: " + i;
}
*/
QMetaObject::invokeMethod(this, "do_Work", Qt::QueuedConnection);
}
void worker::StopWork()
{
qDebug() << "inside StopWork";
stopped = true;
running = false;
//emit stopped();
}
void worker::StartWork()
{
qDebug() << "inside StartWork";
stopped = false;
running = true;
//emit running();
do_Work();
}
You should write
WorkerThread->start();
Or you can use the thread of the ThreadTest object instead the WorkerThread (in this case the WorkerThread is needless):
myWorker->moveToThread(thread()); // this->thread
The slots are not triggered, because you have moved myWork to the thread WorkerThread, but didnot run an event loop in that thread. In threadtest.cpp, add
WorkerThread .start();
after
myWorker = new worker;
WorkerThread = new QThread;
myWorker->moveToThread(WorkerThread);

Is it possible for a worker to stop it's own thread with signal/slot connection in Qt?

I'm trying to implement threaded worker for parallel computation. The problem I encountered is that the quit() slot of thread is not triggered, therefore applications waits at while(thread->isRunning()). Is it possible to stop thread from worker using signal-slot connection between them?
Here is my code:
main.cpp:
#include <QCoreApplication>
#include "workermanager.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WorkerManager workerManager;
workerManager.process();
return a.exec();
}
worker.h:
#include <QObject>
#include <QDebug>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = 0) :
QObject(parent){}
signals:
void processingFinished();
public slots:
void process()
{
qDebug() << "processing";
emit this->processingFinished();
}
};
workermanager.h:
#include "worker.h"
#include <QThread>
class WorkerManager : public QObject
{
Q_OBJECT
public:
explicit WorkerManager(QObject *parent = 0) :
QObject(parent){}
void process()
{
QThread* thread = new QThread;
Worker* worker = new Worker;
connect(thread,SIGNAL(started()),worker,SLOT(process()));
connect(worker,SIGNAL(processingFinished()),thread,SLOT(quit()));
worker->moveToThread(thread);
thread->start();
qDebug() << "thread started";
while(thread->isRunning())
{
}
qDebug() << "thread finished";
//further operations - e.g. data collection from workers etc.
}
};
That while loop blocks your thread and prevents it from processing any signals, if you really want to wait for the thread to finish, you need to start an event loop.
Try this instead:
void process()
{
QThread* thread = new QThread;
Worker* worker = new Worker;
connect(thread,SIGNAL(started()),worker,SLOT(process()));
connect(worker,SIGNAL(processingFinished()),thread,SLOT(quit()));
worker->moveToThread(thread);
QEventLoop loop;
connect(thread, &QThread::finished, &loop, &QEventLoop::quit);
qDebug() << "thread started";
thread->start();
loop.exec();
qDebug() << "thread finished";
//further operations - e.g. data collection from workers etc.
}
But I have to admit I don't really see the point of this code. If you need to wait for the task to finish to keep doing stuff, you might as well run it directly.
There at least your program will be able to process other things (if there are some) in the mean time.