简体   繁体   中英

Is the method 'isActive()' of QTimer threadsafe?

I'm currently thinking about the threadsafety of the QTimer implementation.

In my application I use the bool isActive() method to check if a timer is running or not. As I plan to use this method also from other threads, my thoughts went over to threadsafety considerations.

According to my research the method bool isActive() is not threadsafe.

Here are my assumptions:

The implementation of QTimer ( QTimer source code ) shows that bool isActive() just checks if the member-variable int id; is greater than 0:

inline bool isActive() const { return id >= 0; }

This member variable is initialized at the constructor with INV_TIMER which is a define to -1 . When the timer is started, it will be set to the return-value of the int QObject::startTimer(int interval) .

/*! \overload start()
    Starts or restarts the timer with the timeout specified in \l interval.
    If \l singleShot is true, the timer will be activated only once.
*/
void QTimer::start()
{
    if (id != INV_TIMER)                        // stop running timer
        stop();
    nulltimer = (!inter && single);
    id = QObject::startTimer(inter);
}

When a call to isActive() is executed during QTimer::start() from another thread, in my opinion the returned value of bool isActive() could be invalid.

I would appreciate the opinion of someone who is able to verify my assumptions.

To reach thread safety, I would just wrap my call to the timer with a mutex, like in the code snippet shown below.

class SensorControl : public QObject
{
    Q_OBJECT

public:
    SensorControl();    // inits and interval-settings are done at implementation

    bool Start()
    {
        QMutexLocker lock(&m_mutexTimer);
        return m_pTimer->start();
    }

    void Stop()
    {
        QMutexLocker lock(&m_mutexTimer);
        return m_pTimer->stop();
    }

    bool IsMeasuring() const
    {
        QMutexLocker lock(&m_mutexTimer);
        return m_pTimer->isActive();
    }

private:

    QMutex m_mutexTimer;
    QTimer* m_pTimer;

};

If you want to only call QTimer::isActive from another thread, then your solution looks safe. isActive only accesses the id member variable, so you need to mutex-protect all writes to id , and the read of id from your thread. You did that for isActive and stop , so that looks good.

Note that if you ever call other methods of QTimer that write to id , you will get undefined behaviour. So take care to not call things like QTimer::setInterval() , QTimer::~QTimer() (!) and so on. Also don't use a singleshot timer, as that will write to id in QTimer::timerEvent() .

In general wrapping an existing class and adding mutexes is dangerous, whether that works depends on the internals of said class, and those are hard to check for all cases. Also, internals might change in the next Qt version, maybe in the next version QTimer::timerEvent() will unconditionally change the id , and your solution is not thread safe anymore.

So while your approach works, in general I would recommend against it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM