[Qt-interest] Basic QThread question

Sean Harmer sean.harmer at maps-technology.com
Tue Apr 27 09:40:33 CEST 2010


Hi,

On Tuesday 27 April 2010 08:14:25 Phil wrote:
> Thank you for reading this.
> 
> This is the basic situation.
> 
> My main class polls a hardware device every second which returns an int
> value. The hardware device is slow and so the GUI is blocked for about half
> a second each second.
> 
> To overcome the blocking, the hardware class is now sub-classed from
> QThread and has a function similar to the following as well as a run()
> function:
> 
> int hardware::getValue()
> {
>     return x;
> }
> 
> I can see that the run() function starts each second and then stops as it
> should.
> 
> My question is, how do I have run() return the value x? Should I
> periodically call run() from the main class (hardware.run()) which in turn
> calls getValue() which in turn emits a signal to return x to the main
> class via the signal/slot mechanism?
> 
> It seems a bit convoluted, perhaps there is a more practical method?

It is probably best to use a QTimer with a 1s timeout value in your worker 
thread. Then connect the timeout signal to a slot that queries your device and 
then emits a signal value( int x ) say that you have connected to in the main 
thread. 

You just need to be careful about which thread context your slot gets called 
in because the thread object will have affinity with the main thread not 
itself. The easiest way to do this is to create an object in the run() 
function of your QThread subclass that does the actual work rather than having 
the QThread class do the work.

Something like this:

class DevicePoller : public QObject
{
Q_OBJECT
public:
    DevicePoller( QObject* parent = 0 )
    : QObject( parent ), m_timer( new QTimer( this ) )
    {
        connect( m_timer, SIGNAL( timeout() ), SLOT( poll() ) );
        m_timer->start( 1000 );
    }

public slots:
    void poll()
    {
        // Talk to your device here
        ...
        int x = ...

        // Let the world know the value retrieved
        emit value( x );
    }

signals:
    void value( int x );

private:
    QTimer* m_timer;
};


class PollingThread : public QThread
{
Q_OBJECT
public:
    PollingThread( QObject* parent = 0 )
    : QThread( parent )
    {}

    DevicePoller* poller() const { return m_poller; }

protected:
    virtual void run()
    {
        // Create an object to do the polling
        m_poller = new DevicePoller;

        // Start the event loop
        exec();

        // Clean up
        delete m_poller;
        m_poller = 0;
    }

private:
    DevicePoller* m_poller;
};


Then in your main thread somewhere have something like this:

DevicePoller* m_workerThread = new DevicePoller( this );

// Will use a Qt::QueuedConnection as objects live in different threads
connect( m_workerThread->poller(), SIGNAL( value( int ) ), 
         this, SLOT( processValue( int ) ) ); 

m_workerThread->start();

You should now get signals with the polled values delivered to your object in 
the main thread once a second without blocking anything.

HTH,

Sean



More information about the Qt-interest-old mailing list