Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

creating new thread using Qthread-Qt5

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?

like image 282
geek Avatar asked Jan 10 '23 05:01

geek


2 Answers

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.

like image 103
01d55 Avatar answered Jan 17 '23 12:01

01d55


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

like image 31
user3790229 Avatar answered Jan 17 '23 14:01

user3790229