multithreading - Pause a QThread -


updatethread is-a qthread sets qtimer in updatethread::run() calls slot updatethread::tick() every t ms. based upon condition need pause thread , after some time based upon condition need wake up.


  • is way doing qtimer thing okay ? or should move tick code run , call qthread::start() every t ms ?
  • how can pause , wake threads conditionally
  • or should stop() qtimer , start() latter ?

first of all, shouldn't define slots on qthread subclass , call them within run() - slots executed (by performing cross-thread slot invocation) in context of thread owns updatethread instance (the same 1 created it, unless called movetothread() on it), not in context of thread represented updatethread. remember mnemonic:

in run(), qthread::thread() != this

instead, define slots on qobject subclass create inside run().

ok, out of way, let's have @ timer. qtimer documentation contains following:

in multithreaded applications, can use qtimer in thread has event loop. start event loop non-gui thread, use qthread::exec(). qt uses timer's thread affinity determine thread emit timeout() signal. because of this, must start , stop timer in thread; not possible start timer thread.

(emphasis mine) take particular note of last sentence.

the solution cross-thread call of qtimer::start() , qtimer::stop(). might know cross-thread signal/slot connections. uses same underlying mechanism, exposed in qmetaobject::invokemethod():

class updatethread : public qthread {     q_object private:     qobject * m_timer; // qobject* we're not tempted                        // call functions on     qmutext m_mutex; // protects 'm_timer' public:     explicit updatethread( qobject * parent=0 )         : qthread( parent ), m_timer( 0 ) {}     // ... private:     /* reimpl */ void run() {         qtimer timer;         // ...'timer' setup code goes here...         {             const qmutexlocker locker( &m_mutex );             m_timer = &timer; // publish 'timer' through 'm_timer'         }         // main code of run()         exec(); // start event loop timer's timeout()s                 // , can receive cross-thread method calls         {             const qmutexlocker locker( &m_mutex );             m_timer = 0; // un-publish before delete `timer`         }     } public q_slots:     void starttimer() {         const qmutexlocker locker( &m_mutex );         if ( !m_timer ) return;         // perform cross-thread method call:         qmetaobject::invokemethod( m_timer, "start", qt::queuedconnection );     }     void stoptimer() {         const qmutexlocker locker( &m_mutex );         if ( !m_timer ) return;         // perform cross-thread method call:         qmetaobject::invokemethod( m_timer, "stop", qt::queuedconnection );     } }; 

now, how start/stop timer gui thread. asking alternatives.

  1. move tick() code run(), call updatethread::start() every t milliseconds.

    this suboptimal, create , destroy threads every t ms. thread creation still expensive operation. also, if updatethread::run() isn't done time next call start(), you'll lose timer ticks.

  2. updatethread outlined above.

    this isn't bad, it's not idiomatic multithreading, i'd say. it's solution if timer fires that alone slow down gui thread somehow, though might lose timer ticks way, too.

  3. qthreadpool

    my favourite. move code performs tick() implementation of qrunnable::run(), , queue new runnable on thread pool whenever timer fires. in case, timer naturally live in gui thread, avoiding need cross-thead method calls outlined above. unless gui thread overloaded, won't miss timer ticks. free scaling number of cores in system (if don't want that, don't use qthreadpool::globalinstance() create own instance , call setmaxthreadcount(1)).


Comments