QTimer的方法'isActive()'是线程安全的吗?
Is the method 'isActive()' of QTimer threadsafe?
我目前正在考虑 QTimer
实现的线程安全性。
在我的应用程序中,我使用 bool isActive()
方法来检查计时器是否为 运行。由于我打算在其他线程中也使用此方法,因此我的想法转向了线程安全方面的考虑。
根据我的研究,方法 bool isActive()
不是线程安全的。
这是我的假设:
QTimer
(QTimer source code) 的实现表明 bool isActive()
只是检查成员变量 int id;
是否大于 0:
inline bool isActive() const { return id >= 0; }
此成员变量在构造函数中使用 INV_TIMER
初始化,这是对 -1
的定义。当定时器启动时,它将被设置为 int QObject::startTimer(int interval)
.
的 return 值
/*! \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()
的 returned 值可能无效。
如果有人能够验证我的假设,我将不胜感激。
为了实现线程安全,我会用互斥锁包装我对计时器的调用,如下面的代码片段所示。
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
。您为 isActive
和 stop
做了这件事,看起来不错。
请注意,如果您曾经调用 QTimer
的其他写入 id
的方法,您将得到未定义的行为。所以注意不要调用 QTimer::setInterval()
、QTimer::~QTimer()
(!) 之类的东西。也不要使用单次计时器,因为它将写入 QTimer::timerEvent()
.
中的 id
一般来说,包装现有的 class 并添加互斥量是危险的,这是否有效取决于所述 class 的内部结构,并且很难在所有情况下检查这些。此外,下一个 Qt 版本的内部结构可能会发生变化,也许在下一个版本中 QTimer::timerEvent()
将无条件更改 id
,并且您的解决方案不再是线程安全的。
因此,虽然您的方法有效,但总的来说我不建议采用它。
我目前正在考虑 QTimer
实现的线程安全性。
在我的应用程序中,我使用 bool isActive()
方法来检查计时器是否为 运行。由于我打算在其他线程中也使用此方法,因此我的想法转向了线程安全方面的考虑。
根据我的研究,方法 bool isActive()
不是线程安全的。
这是我的假设:
QTimer
(QTimer source code) 的实现表明 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()
的 returned 值可能无效。
如果有人能够验证我的假设,我将不胜感激。
为了实现线程安全,我会用互斥锁包装我对计时器的调用,如下面的代码片段所示。
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
。您为 isActive
和 stop
做了这件事,看起来不错。
请注意,如果您曾经调用 QTimer
的其他写入 id
的方法,您将得到未定义的行为。所以注意不要调用 QTimer::setInterval()
、QTimer::~QTimer()
(!) 之类的东西。也不要使用单次计时器,因为它将写入 QTimer::timerEvent()
.
id
一般来说,包装现有的 class 并添加互斥量是危险的,这是否有效取决于所述 class 的内部结构,并且很难在所有情况下检查这些。此外,下一个 Qt 版本的内部结构可能会发生变化,也许在下一个版本中 QTimer::timerEvent()
将无条件更改 id
,并且您的解决方案不再是线程安全的。
因此,虽然您的方法有效,但总的来说我不建议采用它。