一 QTimer详解
QTimer类提供了重复和单次触发信号的定时器。
a.void timeout ()定时器超时后,这个信号被发射。
b.void start()开启定时器,它的重载函数void start(int msec),启动或重新启动一个超时时间间隔为毫秒的定时器,如果定时器正在运行,它将被停止和重新启动。
c.void stop()停止定时器.
d.void setInterval(int msec)设置超时间隔(毫秒为单位)。
示例:
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);//start之后,每隔一秒触发一次槽函数
注:以前一直以为开启一个定时器就是开启了个线程,好愚蠢的我!
在一个线程内创建了多个定时器,定时器使用时注意其两个特性:
1、定时器之间不是并行处理数据,而是分片占用主线程资源 ,且定时器完成其对应的slot函数任务后,下一个定时器才会开始执行其slot函数任务;
2、当定时器的间隔时间小于其slot函数任务的执行时间时,一旦定时器timeout时,其slot函数不会终止执行,只是暂停,内部变量仍然保存,而后继续执行。
所以开启一个定时器并不等于开启了个线程
想知道时间片是什么的小伙伴可以看看这个 CPU时间分片、多线程、并发和并行
二 在多线程中开启定时器的示例
示例:达到的效果,开启多个线程执行同一个耗时的操作,每个线程里,每隔多少时间去执行这个操作.
//调用示例
QTimerThread *testObject = new QTimerThread(1);//创建几个线程
testObject->createItem();//调用开始创建线程的函数
testObject->startMultThread();//开启线程的函数
.h
#ifndef QTIMERTHREAD_H
#define QTIMERTHREAD_H
#include
#include
#include
#include "tcpclient.h"
class QTimerThread : public QObject
{
Q_OBJECT
public:
QTimerThread(int iCount);
~QTimerThread();
void createItem();
void startMultThread();
public slots:
void update();
private:
int m_iThreadCount;//开启的线程个数
QList<QTimer*> m_qTimerList;
QList<QThread*> m_threadList;
};
#endif // QTIMERTHREAD_H
.cpp
#include "qtimerthread.h"
#include
QTimerThread::QTimerThread(int iCount)
{
m_iThreadCount = iCount;
}
QTimerThread::~QTimerThread()
{
//对象的销毁顺序也很重要
for(int i = 0; i < m_iThreadCount; i++)
{
m_threadList.value(i)->quit();
m_threadList.value(i)->wait();
m_qTimerList.value(i)->deleteLater();
m_threadList.value(i)->deleteLater();
}
}
void QTimerThread::createItem()
{
for(int i = 0;i < m_iThreadCount;i++)
{
QTimer *timer = new QTimer();
QThread *thread = new QThread();
m_qTimerList.append(timer);
m_threadList.append(thread);
}
}
void QTimerThread::startMultThread()
{
for(int i = 0; i < m_qTimerList.size(); i++)
{
//划重点的部分
/*注:好像还有其他方式可以实现比如把定时器的开启放在connect里面,
感兴趣的小伙伴可以试一试换换顺序这些的是什么效果,
我当时好像都试了一遍,
但是可能是这种方法比较容易理解且不出错才采用了,
实践出真知。*/
m_qTimerList.value(i)->start(5000);
m_qTimerList.value(i)->moveToThread(m_threadList.value(i));
QObject::connect(m_qTimerList.value(i),SIGNAL(timeout()),this,SLOT(update()),Qt::QueuedConnection);
m_threadList.value(i)->start();
}
}
void QTimerThread::update()
{
//这里放需要耗时的操作
}
注:定时器的开启要放在最前面,不然会报错
翻译:QObject::startTimer: QTimer只能用于以QThread启动的线程
注意:
1)QTimer 不能指定parent, 否则 会出现警告 " QObject::moveToThread: Cannot move objects with a parent"。 因为moveToThread 无法移动有parent的object.
2) QTimer 需要用moveToThread 来改变线程相关性. 这样emit signal的时候才会在工作线程.
3)定时器的创建和开启只能在同一个线程中,不然就会报上面的那种错误。
或许你会感兴趣的内容:
Qt封装一个类管理moveToThread( )正确的开启多线程、安全的退出线程的实例
总结:QT 多线程(处理密集时的界面响应保持)注:这里面有讲moveToThread开启线程的方法,很详细了
QT-TCP服务端开启多个线程处理收到多客户端发来的消息示例