问题描述
我需要一个带有计时器的类,该类每100毫秒执行一次任务,该类需要在线程中运行,所以我想将qtimer与qthread结合起来。
我创建了以下代码:
class Worker : public QObject
{
Q_OBJECT
public:
void setEnabled(bool enable);
public slots:
void initialize();
private:
void doWork();
QTimer *m_timer;
}
void Worker::initialize()
{
m_timer = new QTimer(this);
connect(m_timer,&QTimer::timeout,this,&Worker::doWork,Qt::DirectConnection);
m_timer->start(100);
}
void Worker::setEnabled(bool enable)
{
if(enable)
m_timer->start(100);
else
m_timer->stop();
}
int main(int argc,char *argv[])
{
QCoreApplication app(argc,argv);
QThread *thread = new QThread;
Worker *worker = new Worker;
QObject::connect(thread,&QThread::started,worker,&Worker::initialize);
worker->movetoThread(thread);
thread->start();
app.exec();
delete worker;
delete thread;
}
使用以下命令,我可以启用/禁用时间
worker-> setEnabled(false); worker-> setEnabled(true);
我已经测试过并且可以正常工作,但是我想知道这是否正确吗?
感谢您的帮助
解决方法
不,这并不完全正确。
Worker::setEnabled(bool enable)
也应该是一个插槽,因为它直接调用了QTimer::start()
插槽。直接从主线程调用Worker::setEnabled
会导致未定义的行为。您必须使用信号插槽连接才能从主线程安全地调用setEnabled
。
您还应该在构造函数中初始化Worker::m_timer
,而不是将其推迟到initialize()
,这样,如果Worker::setEnabled
的调用早于预期,就不会遇到悬空的指针。 moveToThread
会将Worker
的所有子代都移动了,因此这是完美的举止。
我唯一需要提及的是m_timer不能在构造函数中初始化。请参阅此处来自qt的信息:
顺便说一句,这里要注意的一个非常重要的事情是,您永远不要在QObject类的构造函数中分配堆对象(使用new),因为这种分配是在主线程而不是线程上执行的。 new QThread实例,这意味着新创建的对象然后由主线程而不是QThread实例拥有。这将使您的代码无法正常工作。相反,在这种情况下,应在主函数槽中分配此类资源,例如initialize(),因为在这种情况下,调用该对象时该对象将位于新线程实例上,因此它将拥有该资源。