Является ли метод isActive() в QTimer потокобезопасным?

В настоящее время я думаю о потокобезопасности реализации QTimer.

В моем приложении я использую метод bool isActive(), чтобы проверить, работает ли таймер или нет. Поскольку я планирую использовать этот метод и в других потоках, мои мысли перешли к соображениям безопасности потоков.

Согласно моим исследованиям, метод bool isActive() не является потокобезопасным.

Вот мои предположения:

Реализация QTimer (исходный код QTimer 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);
}

Когда вызов isActive()выполняется во время QTimer::start()из другого потока, на мой взгляд, возвращаемое значение 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;

};

person Philipp Doublehammer    schedule 08.05.2017    source источник
comment
QTimer не является потокобезопасным и даже не реентерабельным. Так что даже мьютекс в вашем коде не сделает его безопасным.   -  person peppe    schedule 08.05.2017


Ответы (1)


Если вы хотите только вызывать QTimer::isActive из другого потока, ваше решение выглядит безопасным. isActive обращается только к переменной-члену id, поэтому вам необходимо защитить от мьютекса все записи в id и чтение id из вашего потока. Вы сделали это для isActive и stop, так что выглядит неплохо.

Обратите внимание, что если вы когда-нибудь вызовете другие методы QTimer, которые пишут в id, вы получите неопределенное поведение. Поэтому постарайтесь не называть такие вещи, как QTimer::setInterval(), QTimer::~QTimer() (!) и так далее. Также не используйте однократный таймер, так как он будет записывать в id в QTimer::timerEvent().

В общем, обертывание существующего класса и добавление мьютексов опасно, работает ли это, зависит от внутреннего устройства указанного класса, и их трудно проверить во всех случаях. Кроме того, внутренние компоненты могут измениться в следующей версии Qt, возможно, в следующей версии QTimer::timerEvent() безоговорочно изменит id, и ваше решение больше не будет потокобезопасным.

Поэтому, хотя ваш подход работает, в целом я бы не рекомендовал его.

person Thomas McGuire    schedule 08.05.2017