2017-05-08 1 views
0

Ich denke gerade über die Threadsicherheit der QTimer Implementierung nach.Ist die Methode 'isActive()' von QTimer threadsafe?

In meiner Anwendung verwende ich die bool isActive() Methode, um zu überprüfen, ob ein Timer läuft oder nicht. Da ich plane, diese Methode auch aus anderen Threads zu verwenden, sind meine Überlegungen zu Thread-Sicherheitsüberlegungen übergegangen.

Nach meinen Recherchen ist die Methode bool isActive() nicht threadsafe.

Hier sind meine Annahmen:

Die Implementierung von QTimer (QTimer source code) zeigt, dass bool isActive() prüft nur, wenn das Mitglied-Variable int id; größer als 0:

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

Diese Membervariable bei der Initialisierung Konstruktor mit INV_TIMER, die eine Definition zu -1 ist. Wenn der Timer gestartet wird, wird er auf den Rückgabewert int QObject::startTimer(int interval) gesetzt.

/*! \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); 
} 

Wenn ein Anruf an isActive() während QTimer::start() von einem anderen Thread ausgeführt wird, könnte der zurückgegebene Wert von bool isActive() meiner Meinung nach ungültig.

Ich würde die Meinung von jemandem schätzen, der in der Lage ist, meine Annahmen zu überprüfen.

Um die Thread-Sicherheit zu erreichen, würde ich meinen Anruf einfach mit einem Mutex an den Timer weiterleiten, wie im unten gezeigten Code-Snippet.

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; 

}; 
+1

QTimer ist nicht threadsafe, und nicht einmal reentrant. Also nicht einmal ein Mutex in deinem Code wird es sicher machen. – peppe

Antwort

1

Wenn Sie wollen nur Anruf QTimer::isActive von einem anderen Thread, dann Ihre Lösung sieht sicher. isActive greift nur auf die Membervariable id zu, so dass Sie alle Schreibvorgänge auf id mutex-schützen und den Thread id von Ihrem Thread lesen müssen. Sie haben das für isActive und stop getan, so dass das gut aussieht.

Beachten Sie, dass wenn Sie jemals andere Methoden von QTimer aufrufen, die auf id schreiben, werden Sie undefiniertes Verhalten erhalten. Achten Sie also darauf, keine Dinge wie QTimer::setInterval(), QTimer::~QTimer() (!) Und so weiter zu nennen. Verwenden Sie auch keinen singeshot Timer, da dieser in id in QTimer::timerEvent() schreibt.

Im Allgemeinen ist das Wrapping einer vorhandenen Klasse und das Hinzufügen von Mutexen gefährlich. Ob das funktioniert, hängt von den Interna der Klasse ab, und diese sind in allen Fällen schwer zu überprüfen. Auch Interna können sich in der nächsten Qt-Version ändern, vielleicht wird in der nächsten Version QTimer::timerEvent() die id bedingungslos geändert, und Ihre Lösung ist nicht mehr Thread-sicher.

Also während Ihr Ansatz funktioniert, würde ich im Allgemeinen empfehlen, dagegen.