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

你可能感兴趣的:(《Qt,项目实战经历全记录》,qt,多线程,定时任务)