Search code examples
c++qtqthreadqtimer

QTimer running in QThread


I need a class with a timer which will do a task every 100msec, this class need to run in a thread, so I would like to combine qtimer with qthread.

I have created the following code:

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;
}

With the following commands I could then enable/disable the time

worker->setEnabled(false); worker->setEnabled(true);

I have tested and it works fine, but I would like to know if this is the correct way?

Thanks for the help


Solution

  • No, it's not entirely correct.

    Worker::setEnabled(bool enable) should be a slot too, as it's invoking the QTimer::start() slot directly. Calling Worker::setEnabled directly from the main thread then results in undefined behavior. You must use a signal-slot connection to invoke setEnabled safely from the main thread.

    You also should have initialized Worker::m_timer in the constructor rather than deferring it until initialize(), so you don't run into a dangling pointer if Worker::setEnabled was invoked earlier than expected. moveToThread will move all children of Worker with it, so that's perfectly sane behavior.