Qt 之 线程与QTimer

背景

项目中,经常会用到定时器,定时去查询某个东西或者定时去执行某个函数,大多情况下,策略都是QThread 结合 QTimer来实现,然而实现中,经常会遇到这样的错误警告:

QObject::killTimer: Timers cannot be stopped from another thread
QObject: Cannot create children for a parent that is in a different thread.

如何正确的结合QThread和QTimer呢,本来来做个简单总结

在QThread run函数内创建QTimer

代码如下:

mythread.cpp

void mythread::run()
{
    m_pTimer = new QTimer(); //不能加this
    m_pTimer->setInterval(1000);

    connect(m_pTimer, &QTimer::timeout, this, &mythread::timeoutSlot);
    connect(m_pTimer, &QTimer::timeout, [=]{
        //m_pTimer->stop();
        qDebug() << QString::fromLocal8Bit("fun run 线程id = ") << QThread::currentThread();
    });
    m_pTimer->start();
    this->exec();
}

void mythread::timeoutSlot()
{
    //m_pTimer->stop();
    qDebug() << QString::fromLocal8Bit("timeoutSlot 线程id = ") << QThread::currentThread();
}

主线程MainWindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() << QString::fromLocal8Bit("主线程:") << QThread::currentThread();
    pth = new mythread;
    connect(pth,&QThread::finished,[]{
        qDebug() << "thread end";
    });
    pth->start();
}

MainWindow::~MainWindow()
{
    delete ui;
}

注意有几点:
1.不能像下面这样给定时器指定父对象

m_pTimer = new QTimer(this);

否则会出现以下警告:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is TestThread(0x709d88), parent's thread is QThread(0x6e8be8), current thread is TestThread(0x709d88) 

因为mythread对象是在主线程中创建的,它的QObject子对象也必须在主线程中创建。所以不能指定父对象为mythread。

2 同样的超时处理函数,实现方式不同,结果不同,一种是直接在run里面的lamba,一种是自定义的槽函数timeoutSlot(),所执行的线程确实不一样

connect(m_pTimer, &QTimer::timeout, this, &mythread::timeoutSlot);
    connect(m_pTimer, &QTimer::timeout, [=]{
        //m_pTimer->stop();
        qDebug() << QString::fromLocal8Bit("fun run 线程id = ") << QThread::currentThread();
    });

结果是:

"主线程:" QThread(0x1b567ea7a00)
"fun run 线程id = " mythread(0x1b569eb06a0)
"timeoutSlot 线程id = " QThread(0x1b567ea7a00)
"fun run 线程id = " mythread(0x1b569eb06a0)
"timeoutSlot 线程id = " QThread(0x1b567ea7a00)

可以看出 只有在run函数内定义的变量或者函数,才是真正在新线程内执行的。

3 run函数内必须加上这句事件循环

this->exec();

不然线程就立马执行结束了。

使用moveToThread

c++处理类

class NetLiveWorker : public QObject
{
    Q_OBJECT
public:
    NetLiveWorker()
    {
        m_isLive = false;
    }

    bool IsHostOnline(QString strHostName, int nTimeoutmSeconds = 2000);
   bool IsWebOk(){
        return IsHostOnline("https://www.baidu.com/", 2000);
    }
public slots:
    void onTimeout()
    {
        m_isLive = IsWebOk();
        qDebug()<<"onTimeout  threadid = "<<QThread::currentThreadId() << m_isLive;
    }

private:
    bool m_isLive;
};

MainWindow.h

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    NetLiveWorker netLive;
    QThread thread;
    QTimer timer;
};

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() << "main thread id = " << QThread::currentThreadId();
    QObject::connect(&timer, SIGNAL(timeout()), &netLive, SLOT(onTimeout()));
    timer.start(4000);
    netLive.moveToThread(&thread);
    thread.start();
}

MainWindow::~MainWindow()
{
    timer.stop();
    thread.quit();
    thread.wait();
    delete ui;
}

结果如下:

main thread id =  0x35c4
Worker::onTimeout threadid =  0x3428 true
Worker::onTimeout threadid =  0x3428 true
Worker::onTimeout threadid =  0x3428 true
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值