项目中,经常会用到定时器,定时去查询某个东西或者定时去执行某个函数,大多情况下,策略都是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呢,本来来做个简单总结
代码如下:
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();
不然线程就立马执行结束了。
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