Blabla... thread is tiny process that share the memory.
- Thread can run on multicore CPUs. But how about The C10K problem?
- Qt GUI must run in "main thread"
- Simultaneous access an shared object will be faster that communicate in process, but it's also dangerous.
- Some cases will cause danger
- static members
- singletons
- global data
- How to use thread safely thread safe and reentrant
We use thread to make processing faster and keep the GUI thread unblock
Threads are dangerous. When we want to use thread at a time we'd better consider some alternatives.
- QEventLoop::processEvents() Just event loop, this solution doesn't scale well, because the call to processEvents() unpredictable.
- QTimer For short task it'll conveniently, but time consuming task'll block the GUI thread.
- [Network stuff]
- QSocketNotifier
- QNetworkAccessManager
- QIODevice::readyRead()
- QConcurrent
Functional way to perform an computation. If use the
run()
method for the target function it'll run in a separate Thread from the defaultQThreadPool
.
The Qt Thread Scenes
- One call : Just run a method and quit.
[Solutions]
QtConcurrent::run()
- Derive a class from
QRunnable
and run it in the global thread poll withQThreadPool::globalInstance()->start()
- Derive a class from
QThread
, reimplement theQThread::run()
method and useQThread::start()
to run it.
- One call : Perform on all items of a container(such as produce thumbnails from images)
[Solutions]
QtConcurrent::map()
QtConcurrent::filter()
- Other
QtConcurrent
methods...
- One call : Long running operation, during the course status information should be sent to the GUI thread.
[Solutions]
- Use
QThread
, reimplementrun
andemit
signals as needed, thenconnect
the signals to the GUI thread's slots.
- Use
- Permanent : Need to communicate to and from the worker thread.
[Solutions]
- Derive a class from
QObject
and implement the necessary slots and signals, move the object to a thread with a running event loop and communicate with the object over queued signal/slot connections
- Derive a class from
- Permanent :
Although the class is called
QSocketNotifier
, it is normally used for other types of devices than sockets.QTcpSocket
andQUdpSocket
provide notification through signals, so there is normally no need to use a QSocketNotifier on them. [Solutions]- Same as above but also use a timer in worker thread to implement polling. To do this, you'd better use
QSocketNotifier
- Same as above but also use a timer in worker thread to implement polling. To do this, you'd better use
The easy way to use QThread
:
- Derive a class from
QThread
, let's call itSomeThread
- Implement the
run()
method - Create an instance of
SomeThread
, then call it'sstart()
method. Note: Exiting the program when another thread is still busy is a programming error, therefore, we need to call thread'swait()
method before exiting.
-
The thread where the
QObject
lives should have an event loop to deliver the event. Callexec()
method to start an event loop. -
On Linux, Valgrind and Helgrind can help detect threading errors.
-
The anatomy of
QThread
:- Before
run()
is executed,QThread
lives in the old thread.run()
started, mean new thread started. - Most
QThread
methods are the thread's control interface and are meant to be called from the old thread..... - The parameter variables pass to the sub thread should not touch them from main thread anymore.
- Before
-
A
QObject
's parent must always be in the same thread. We must be careful when we alloc anQObject
inrun()
method.void HelloThread::run() { QObject *object1 = new QObject(this); //error, parent must be in the same thread QObject object2; // OK QSharedPointer <QObject> object3(new QObject); // OK }
QObject *object1 = new QObject(this);
is error, becausethis
object is in main thread.
- Between
lock()
andunlock()
if an exception occurs it'll never reach theunlock()
method then all related threads'll frozen. We useQMutexLocker locker(&mutex)
to prevent this problems like this. - Most Qt methods aren't thread-safe.
- Mutexes will introduce deadlock problems.
Every thread may have it's own event loop. A safe way to calling a slot in another thread is by placing that call in another thread's event loop. So how is it possible to put a method invocation in an event loop? [Solutions]
- Make queued signal/slot connections
- Post an event with
QCoreApplication::postEvent()
.
How can we obtain a worker thread's result? In many cases, a blocking wait isn't acceptable. [Solutions] The same as above --
You'll know:
- How to communicate with a running thread.
- How a
QObject
can be placed in another thread, providing service to the main thread.
We use thread pool beacuse creating and destroying threads frequently can be expensive.
[QThread vs QRunnable] :
-
QThread is low-level threading primitive to create and handle threads.
-
QRunnable is high-level concept (command pattern) and is thread independent. QRunnable objects can be executed in another thread but doesn't have to be.
// hellothreadpool/main.cpp class Work : public QRunnable { public: void run() { qDebug() << "Hello from thread " << QThread::currentThread(); } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Work work; work.setAutoDelete(false); QThreadPool *threadPool = QThreadPool::globalInstance(); threadPool->start(&work); qDebug() << "hello from GUI thread " << QThread::currentThread(); threadPool->waitForDone(); return 0; }
work.setAutoDelete(false);
: work thread not destroyed after it have finished running.
Already learnt it, see the sample code in project AllForTest
Shows how to communicate from worker thread to GUI thread. [easy]
-
Use signal/slot to communicate from worker to GUI thread
QObject::connect(thread, SIGNAL(signalInThread()), widget, SLOT(slotInGUIThread()), Qt::QueuedConnection)
-
Use
QTimer
to receive time change event from system
Show how to communicate from GUI thread to worker thread (send task to worker thread).
- Derive a class from
QThread
(SomeThread
) - Derive a class from
QObject
define some methods do the work(WorkerObject
) - Create a
SomeThread
object(thread
) andWorkerObject
object(worker
), moveworker
tothread
byworker->moveToThread(thread)
- In GUI thread, send task to worker thread by:
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection)
- Video : Training Day at Qt Developer Days 2009
- Document: Thread Support in Qt
- Examples : QThread and QtConcurrent
- Book : Advanced Qt Programming by <Mark Summerfield, Prentice Hall>
- Threading Basics
- Created at: [2013-04-07 15:49]
- Finished at: [2013-04-09 14:32]