origin URL : http://cdumez.blogspot.com/2011/03/worker-thread-in-qt-using-signals-slots.html
Saturday, March 12, 2011
Worker Thread in Qt using Signals & Slots
Signal-slot connections across threads
Let's have a look at the QObject::connect() method:
1
2
3
| bool QObject::connect( const QObject
*sender, const char
* signal , const QObject *receiver, const char *method,
Qt::ConnectionType type = Qt::AutoConnection); |
- It is safe to use a queued connection between two different threads (direct connection is not)
- The slot is executed in the receiver's thread. This means that we can emit a signal from the main thread and connect it to a slot in our worker thread. The processing is then done in the worker thread.
Simple example
A QObject instance is said to live in the thread in which it is created. Events to that object are dispatched by that thread's event loop.
Visual representation of our threads |
Sorter class: header
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| #include <QThread> #include
<QVector> /*! Class
for doing work (sorting) in a worker thread */ class
Sorter : public
QThread { Q_OBJECT public : /*! Default
constructor */ Sorter(QObject
*parent = 0); /*! Sorts asynchronously a vector in a worker
thread */ void sortAsync( const
QVector< int > &list); signals: /*! * Internal
signal used to communicate with * the worker thread. */ void sortingRequested( const QVector< int >
&list); /*! Signal
emitted once the vector is sorted */ void vectorSorted( const QVector< int >
&list); protected : void run(); private : /*! *
Boolean indicating if the worker thread is ready * to process requests. */ bool
m_ready; }; |
Also note the use of QMetaType::qRegisterMetaType() before connecting our signals/slots. Whenever a signal is queued, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes. If you forget this, you will get the following error:
QObject.connect: Cannot queue arguments of type 'QList<int>'Sorter class: source
(Make sure 'QList<int>' is registered using qRegisterMetaType().)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| #include <QMetaType> #include
<QDebug> #include "sorter.h" #include
"sorter_p.h" Sorter::Sorter(QObject
*parent): QThread(parent),
m_ready( false ) { qDebug() <<
Q_FUNC_INFO << QThread::currentThreadId(); // Main Thread //
Start the worker thread start(); // Wait for the worker thread to be ready; while (!m_ready)
msleep(50); } void
Sorter::sortAsync( const QVector< int > &v) { qDebug() << Q_FUNC_INFO <<
QThread::currentThreadId(); // Main
Thread emit
sortingRequested(v); } void
Sorter::run() { qDebug() << Q_FUNC_INFO <<
QThread::currentThreadId(); // Worker
Thread // This QObject
lives in the worker thread SorterWorker
worker; // DO NOT define 'this'
pointer as parent // We need to
register QList<int> because it is not known // to Qt's meta-object system qRegisterMetaType< QVector< int > >( "QVector<int>" ); // Pass sorting requests to SorterWorker in the
worker thread connect( this ,
SIGNAL(sortingRequested(QVector< int >)), &worker,
SLOT(doSort(QVector< int >)) /*,
Qt::QueuedConnection*/ ); // Forward the signal to the clients connect(&worker, SIGNAL(vectorSorted(QVector< int >)), this , SIGNAL(vectorSorted(QVector< int >)) /*, Qt::QueuedConnection*/ ); // Mark the
worker thread as ready m_ready =
true ; // Event loop
(necessary to process signals) exec(); } </ int > |
SorterWorker class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| #include <QObject> #include
<QVector> #include <QThread> #include
<QDebug> /*! Class
doing the actual work (sorting) */ class SorterWorker: public
QObject { Q_OBJECT signals: /*! Signal emitted once the vector is sorted */ void vectorSorted( const QVector< int > &v); public slots: /*!
Method taking care of the actual sorting */ void doSort( const QVector< int > &v) { qDebug() << Q_FUNC_INFO <<
QThread::currentThreadId(); // Worker
Thread QVector< int > v_sorted
= v; qSort(v_sorted); emit vectorSorted(v_sorted); } }; |
How to use our worker thread
1
2
3
4
| Sorter t; connect(&t, SIGNAL(vectorSorted(QVector< int >)), SLOT(handleVectorSorted(QVector< int >))); t.sortAsync(QVector< int >()
<< 1 << 3 << 2); |
Debugging
1
| qDebug() << Q_FUNC_INFO <<
QThread::currentThreadId(); |
QtConcurrent alternative
1
| QFuture<T> QtConcurrent::run(Function func, ...); |
6 comments:
-
I think We dont need to subclass QThread, and this example can be made very simple. Qt devs have already said that subclassing QThread is not a good idea.
-
From the official QThread documentation:
"To create your own threads, subclass QThread and reimplement run()." -
@Christoper: that statement in the docs dates from before Qt 4.4, when the default implementation of QThread::run() was changed so that it now calls QThread::exec() - and so there is no longer any need to subclass QThread.
This is discussed in the following post on Qt Labs (and in the extensive chain of comments below it).
http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/ -
as rightly pointed out by Gareth, this is the exact post i was refereing to when i said
"Qt devs have already said that subclassing QThread is not a good idea."
This is an old and wrong way of doing things. -
I used the same implementation as the blogger's for many years. Since this is due to a change introduced in 4.4 and the qt document has not been changed to reflect the new design, it is the document to blame.
http://bugreports.qt.nokia.com/browse/QTBUG-16358 -
I know about this blog article. Please note that I'm not using "moveToThread(this);" in my constructor. I believe that my use of QThread is correct although there may be a simpler solution.
What would be a cleaner solution then? If I try to follow the directions in the Qt blog article, I get the following code: http://pastebin.com/N2V4Vdk2
Frankly, I would not say it is any better. Am I missing something?
'Research > Programming' 카테고리의 다른 글
sqlite 파일, 테이블, 쿼리, 업데이트 (0) | 2011.05.18 |
---|---|
pthread_cond_wait (0) | 2011.05.11 |
An Introduction to SQLite (0) | 2010.02.01 |
Qt, undefined reference to `vtable for (1) | 2010.01.26 |
Makefile: 변수 출력하기 (0) | 2009.12.14 |