使用QThread-Qt5创建新线程

4

我正在尝试创建一个名为gpsthread的新线程,它应该在后台运行并存储值。

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();
}
};

我的主类是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();

我也尝试过这个方法

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();
}
};

但它出现了错误提示
 QObject: Cannot create children for a parent that is in a different thread

如果我在构造函数中创建对象,那么仍然会出现相同的错误,因为对象将在主线程中创建。 如何解决这个问题?
2个回答

10

继承QThread并不是推荐的用法。QThread是一个完整的类,可以运行事件循环,这通常是您所需要的。 文档 建议使用从QObject继承并在槽中完成工作的工作对象。将工作对象移动到QThread中。当发送连接信号时,槽将在正确的线程中运行。

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();
}

如果你希望计时器在另一个线程中继续运行,QTimer::start 是一个槽函数。

感谢您的解释,这确实是使用线程的正确方式。 - Goddard
你不是忘了加上 timer->setSingleShot(true); 吗? - Jack
@Jack 的单次操作并不在问题中,因此我在我的答案中没有添加它。鉴于超时时间很长,人们可以合理地假设工作人员需要在规定的时间间隔内处理 GPS 数据。 - 01d55

1
QObject: Cannot create children for a parent that is in a different thready

这是因为在run()中的t = new QTimer(this)正在子线程中创建一个对象,但指向gpsthreadthis在主线程中。一个简单的解决方案是t = new QTimer()而不带有父级,并在析构函数中删除定时器。以下是示例:

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;
};

很快你会发现控制台打印:
Parent thread 0x3b28
inside gps thread 0x3f10
processgps() 0x3b28
processgps() 0x3b28
processgps() 0x3b28
processgps() 0x3b28

这意味着您的子线程中 processgps() 无法正常工作。原因是该插槽是 gpsthread 的成员,而该线程位于主线程中。一个简单的解决方案是直接调用 processgps() 并使用 sleep() 作为计时器。
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;
};

这不是一个好的解决方案,推荐的方法是创建一个工作线程来完成所有工作,然后按照QThread文档中所说使用QObject::moveToThread()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接