QTimer 线程的方法 'isActive()' 是安全的吗?



我目前正在考虑QTimer实现的线程安全性。

在我的应用程序中,我使用bool isActive()方法来检查计时器是否正在运行。由于我计划也从其他线程使用此方法,因此我的想法转向了线程安全注意事项。

根据我的研究,该方法bool isActive()不是线程安全的。

以下是我的假设:

QTimer(QTimer 源代码)的实现表明,bool isActive()只检查成员变量int id;是否大于 0:

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

此成员变量在构造函数中使用INV_TIMER初始化,这是要-1的定义。当计时器启动时,它将设置为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);
}

当在另一个线程的QTimer::start()期间执行对isActive()的调用时,在我看来,bool isActive()的返回值可能是无效的。

我将不胜感激能够验证我的假设的人的意见。

为了达到线程安全,我只需使用互斥锁包装对计时器的调用,如下所示的代码片段。

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

如果只想从另一个线程调用QTimer::isActive,则您的解决方案看起来很安全。isActive仅访问id成员变量,因此您需要互斥保护对id的所有写入,以及从线程读取id。你这样做是为了isActivestop,所以看起来不错。

请注意,如果你调用其他写入idQTimer方法,你会得到未定义的行为。所以要注意不要称呼QTimer::setInterval()QTimer::~QTimer()(!)等东西。也不要使用单次计时器,因为这会在QTimer::timerEvent()中写入id

一般来说,包装现有类并添加互斥体是危险的,这是否有效取决于该类的内部结构,并且很难在所有情况下检查这些内部。此外,内部结构可能会在下一个Qt版本中发生变化,也许在下一个版本中QTimer::timerEvent()将无条件地更改id,并且您的解决方案不再线程安全。

因此,虽然您的方法有效,但总的来说,我建议不要这样做。

最新更新