在QThread中运行的QTimer

问题描述

我需要一个带有计时器的类,该类每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(),因为在这种情况下,调用该对象时该对象将位于新线程实例上,因此它将拥有该资源。