QThread::wait: Thread tried to wait on itself

调用QThread的wait()方法时,报警:QThread::wait: Thread tried to wait on itself

原因:在自己的线程中调用线程的wait()方法。

解决方法:在线程外的其他线程中,调用线程的wait()方法。

示例代码如下:

MyObject.h

#ifndef MYOBJECT_H
#define MYOBJECT_H

#include <QObject>
#include <QThread>

class MyObject : public QObject
{
    Q_OBJECT
public:
    explicit MyObject(QObject *parent = nullptr);
    ~MyObject();
    
    void init();
    void quitThread();
    
    void test1();

public Q_SLOTS:
    void slotTest();
    
private:
    QThread *m_thread = nullptr;    
};

#endif // MYOBJECT_H

MyObject.cpp

#include "MyObject.h"
#include <qdebug.h>

MyObject::MyObject(QObject *parent) : QObject(parent)
{
    init();
}

MyObject::~MyObject()
{
    qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
    
    quitThread();
}

void MyObject::init()
{
    m_thread = new QThread();
    connect(m_thread, &QThread::finished, m_thread, &QThread::deleteLater);
    connect(m_thread, &QThread::finished, this, [] {
        qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
    });
    
    moveToThread(m_thread); // 将该对象移入线程中
    m_thread->start();
}

void MyObject::quitThread()
{
    qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
    
    if (m_thread) {
        m_thread->quit();
        m_thread->wait();
    }
}

void MyObject::test1()
{
    qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
}

void MyObject::slotTest()
{
    qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
}

创建一个对话框,在对话框中测试:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include "MyObject.h"

class Dialog : public QDialog
{
    Q_OBJECT    
public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();
    
private:
    void init();
    
private:
    QPushButton *m_btnTest = nullptr;
    QPushButton *m_btnRelease = nullptr;
    MyObject *m_obj = nullptr;
    
};
#endif // DIALOG_H

dialog.cpp

#include "dialog.h"
#include <qboxlayout.h>
#include <qthread.h>
#include <qdebug.h>

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    init();
}

Dialog::~Dialog()
{
}

void Dialog::init()
{
    setWindowTitle("线程测试");
    setFixedSize(360, 160);
    
    m_btnTest = new QPushButton("测试", this);
    m_btnTest->setFixedSize(100, 36);
    m_btnRelease = new QPushButton("释放对象", this);
    m_btnRelease->setFixedSize(100, 36);
    m_obj = new MyObject();     // 不需指定父对象
    
    qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
    
    QHBoxLayout *lay = new QHBoxLayout(this);
    lay->addWidget(m_btnTest);
    lay->addWidget(m_btnRelease);
    
    connect(m_btnTest, &QPushButton::clicked, this, [this] {
        if (m_obj) {
            m_obj->test1();
            QMetaObject::invokeMethod(m_obj, "slotTest", Qt::QueuedConnection);
        }
    });
    
    connect(m_btnRelease, &QPushButton::clicked, this, [this] {
        if (m_obj) {
            m_obj->deleteLater();
            m_obj = nullptr;
        }
    });
}

运行界面如下:

点击【测试】按钮,打印信息如下所示:

void Dialog::init() 0x43f4
void MyObject::test1() 0x43f4
void MyObject::slotTest() 0x2790

由此可见,主线程的线程ID为0x43f4,子线程的线程ID为0x2790

点击【释放对象】按钮,打印信息如下所示:

virtual MyObject::~MyObject() 0x2790
void MyObject::quitThread() 0x2790
QThread::wait: Thread tried to wait on itself

由于使用的是MyObjec::deleteLater()函数,MyObjectt的析构函数是在子线程中执行的,子线程的退出也是在子线程中执行的,因而报警,且线程退出失败(没有执行QThread::finished)

代码修正:在释放MyObjec对象时,使用delete m_obj,代码如下:

    connect(m_btnRelease, &QPushButton::clicked, this, [this] {
        if (m_obj) {
            delete m_obj;
            m_obj = nullptr;
        }
    });

点击【测试】和【释放对象】按钮时,打印信息如下:

void Dialog::init() 0x1460
void MyObject::test1() 0x1460
void MyObject::slotTest() 0x644
virtual MyObject::~MyObject() 0x1460
void MyObject::quitThread() 0x1460
MyObject::init()::<lambda()> 0x644

由此可见,子线程的退出操作是在主线程中完成的,不仅没有报错,而且线程也成功退出了(执行了线程退出槽函数)

资源文件下载链接(免费):

https://download.csdn.net/download/ouyangxiaozi/89616335

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宏笋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值