devdays2007 - multi-threading in qt
Post on 18-Apr-2015
117 Views
Preview:
TRANSCRIPT
Multi-threading in QtBradley T Hughes
2
Introduction
Bradley T Hughes Joined Trolltech in May, 2000 Senior Software Engineer Team Lead for the Qt Platform Team Open Source Programmer
3
Agenda
Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4
4
Thread Support in Qt
What can I do with Qt? Platform independent multi-threading Start threads Synchronize threads Store per-thread data
5
Thread Support in Qt
Qt provides much more... Thread-affinity in QObject Per-thread event loops Post events to any thread Signals and slots across threads Thread-safe reference counting
6
Agenda
Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4
7
Classes
QThread Abstract class
Must reimplement 'void run()' void start() bool wait(ulong timeout) void terminate() - DO NOT USE bool isFinished() bool isRunning()
8
Classes
QThread QObject subclass
SIGNAL(started()) SIGNAL(finished()) SIGNAL(terminated())
Per-thread event loop int exec() SLOT(quit())
9
Examples
class MyThread : public QThread{ Q_OBJECTpublic: void run() { // do some work }};
10
Examples
void MyClass::startThread(){ myThread = new MyThread; connect(myThread, SIGNAL(finished()), SLOT(threadFinished())); thread->start();}
11
Examples
void MyClass::threadFinished(){ // myThread is finished ...
// cleanup delete myThread; myThread = 0;}
12
Classes
QMutex Mutual-exclusion primitive Recursive and non-recursive (default) modes void lock(), bool tryLock() void unlock()
13
Examples
void MyQueue::queueNew() { // protect data, not code mutex.lock(); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity); mutex.unlock();}
14
Classes
QMutexLocker Uses RAII Automatically lock/unlock a QMutex void unlock(), void relock() Starting with Qt 4.2, keeps state
Destructor does not unlock if you call unlock()
15
Examples
void MyQueue::queueNew(){ QMutexLocker locker(&mutex); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity);}
16
Examples
void MyClass::complexFunction(){ QMutexLocker locker(&mutex); if (...) return; // unlocked try { ... } catch { ... throw; // unlocked }} // unlocked
17
Classes
QWaitCondition Condition variable Thread waits until told to continue Used together with non-recursive QMutexes bool wait(QMutex *, ulong timeout) void wakeOne(), void wakeAll()
18
Examples
Entity *MyQueue::dequeue(){ QMutexLocker locker(&mutex); while (queue.isEmpty()) waitCondition.wait(&mutex); return queue.takeFirst();}
19
Examples
void MyQueue::queueNew(){ QMutexLocker locker(&mutex); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity); waitCondition.wakeOne();}
20
Classes
QSemaphore Simple counting semaphore Constructor initializes available resources void acquire(int), bool tryAcquire(int) void release(int) int available()
21
Examples
void Producer::run(){ for(int i = 0; i < DataSize; ++i) { freeBytes.acquire(); buffer[i] = qrand()%4; usedBytes.release(); }}
22
Examples
void Consumer::run(){ for(int i = 0; i < DataSize; ++i) { usedBytes.acquire(); file.write(buffer[i]); freeBytes.release(); }}
23
Classes
QReadWriteLock Shared-exclusive lock Multiple readers, single writer void lockForRead(), bool tryLockForRead() void lockForWrite(), bool tryLockForWrite() void unlock()
24
Examples
bool MyQueue::find(Entity *e){ bool found = false; readWriteLock.lockForRead(); foreach (Entity *q, queue){ if (found = (q == e)) break; } readWriteLock.unlock(); return found;}
25
Examples
void MyQueue::queueNew(){ readWriteLock.lockForWrite(); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity); readWriteLock.unlock();}
26
Classes
QReadLocker and QWriteLocker RAII again This time on QReadWriteLock void unlock(), void relock() Starting with 4.2, also keeps state
27
Examples
bool MyQueue::find(Entity *e){ QReadLocker locker(&lock); foreach (Entity *q, queue){ if (q == e) return true; } return false;}
28
Examples
void MyQueue::queueNew(){ QWriteLocker locker(&lock); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity);}
29
Classes
QThreadStorage Typesafe per-thread data storage Data deleted when thread exits bool hasLocalData() T localData(), void setLocalData(T) Stores points to data
Store by value? Partial template specialization not
supported in MSVC 6.0, .NET 2002
30
Examples
QThreadStorage<Queue *> cache;
void MyQueue::done(Entity *e){ if (!cache.hasLocalData()) { Queue *q = new Queue; cache.setLocalData(q); } cache.localData()->append(e);}
31
Examples
void MyQueue::queueNew(){ Queue *c = cache.localData(); Entity *entity = (!c || c->isEmpty()) ? new Entity : c->takeFirst(); QMutexLocker locker(&mutex); queue.append(entity);}
32
Agenda
Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4
33
Concepts
Thread affinity in QObject Object belongs to a thread That thread delivers events to object Default is the thread that created the object Change with QObject::moveToThread() Per-thread event loops
34
Pop Quiz
What is the thread affinity of QApplication?
35
Pop Quiz
int main(int argc, char **argv){ QApplication app(argc, argv); qDebug() << app.thread();}
36
Pop Quiz
What is the thread affinity of QApplication?
Answer: The main() thread. Qt creates a QThread object that represents the main() thread, so app.thread() returns a valid pointer.
37
Pop Quiz
What's the thread affinity of a QTimer created in a QThread::run() reimplementation?
38
Pop Quiz
void MyThread::run(){ QTimer timer; qDebug() << timer.thread();}
39
Pop Quiz
What's the thread affinity of a QTimer created in a QThread::run() reimplementation?
Answer: The MyThread instance. Since run() is called by the new thread context, timer.thread() is the same as the 'this' pointer.
40
Pop Quiz
What is the affinity of a QThread instance?
41
Pop Quiz
int main(int argc, char **argv){ QApplication app(argc, argv); QThread thread; qDebug() << thread.thread();}
42
Pop Quiz
What is the affinity of a QThread instance?
Answer: The main() thread. The QThread instance has affinity to thread that created it, not to itself. In other words, the thread is not responsible for delivering its own events. More on this later...
43
Concepts
Default thread affinity is the current thread Objects associated with thread that created them
Code examples from quiz show this clearly
Of course, thread affinity can be changed...
44
Examples
void MyObject::downloadFile(){ DlThread *thr = new DlThread; Downloader *dl = new Downloader;
// move 'dl' to another thread dl->moveToThread(thr);
...
45
Examples
connect(thr,SIGNAL(started()), dl,SLOT(loadDown())); connect(dl,SIGNAL(finished()), thr,SLOT(quit())); connect(thr,SIGNAL(finished()), this,SLOT(loadedDown())); // start downloading thread->start();}
46
Examples
class DlThread : public QThread{ Q_OBJECTpublic: void run() { exec(); }};
47
Concepts
Posted events QApplication::postEvent() Schedules an event for delivery Different from sendEvent() Threads handle events for their objects
48
Examples
void postAnEventTo(QObject *object){ QEvent *event = new QEvent(QEvent::User); QApplication::postEvent(object, event); // event not delivered yet!}
49
Examples
bool sendAnEventTo(QObject *object){ QEvent event(QEvent::User); QApplication::sendEvent(object, &event); // event has been delivered return event.isAccepted();}
50
Concepts
Signals and slots Communication between objects Qt::ConnectionType Direct: Slots called in context of emitter Queued: Posts an event to receiver Auto: Chooses Direct or Queued based on:
Current thread Sender's thread Receiver's thread
51
Examples
void MyObject::createSomeObject(){ SomeObject *receiver = new SomeObject; connect(this, SIGNAL(signal())), receiver, SLOT(slot())), Qt::QueuedConnection);}
void MyObject::emitSignal(){ emit signal(); }
52
Examples
// Tip: call a slot by nameQMetaObject::invokeMethod( object, “slot”);
// Tip: pass an argumentQMetaObject::invokeMethod( object, “setText”, QString(“Hello World”));
53
Examples
// Tip: but not right nowQMetaObject::invokeMethod( object, “setText”, Qt::QueuedConnection, QString(“Hello World”));
54
Concepts
Implicit sharing Copy-on-write
All shared classes are implicit All use atomic reference counting
55
Examples
void MyThread::run(){ QString string; forever { // implicit sharing in action string = readLargeFile(); // just pass a copy emit dataReady(string); }}
56
Examples
// atomic ref count != thread-safe!QString string;
void MyThread::run(){ forever { // WRONG, cannot copy/modify // at the same time string = format(string); }}
57
Examples
QMutex mutex;QString string;
void MyThread::run(){ forever { // RIGHT, protect shared data QMutexLocker locker(&mutex); string = format(string); }}
58
Agenda
Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4
59
New in 4.3
Qt::BlockingQueuedConnection New connection type Mostly the same as QueuedConnection But current thread blocks until slot called Should only be used for receivers in a different thread
60
Examples
connect( sender, SIGNAL(signal()), receiver, SLOT(slot()), Qt::BlockingQueuedConnection);
QMetaObject::invokeMethod( object, “methodName”, Qt::BlockingQueuedConnection);
61
New in 4.3
Posted event priorities Numerical priority can be given to any posted event Higher values have higher priority
4 is higher than zero, zero is higher than -2 Convenience enum, Qt::EventPriority
Qt::HighEventPriorty = 1 Qt::NormalEventPriority = 0 (default) Qt::LowEventPriority = -1
62
Examples
// posted with default priority (0)QApplication::postEvent(r, e1);QApplication::postEvent(r, e2);// higher priorityQApplication::postEvent(r, e3, 1);// lower priorityQApplication::postEvent(r, e4, -1);
// delivery order: e3, e1, e2, e4
63
New in 4.3
Timed try-locking Blocks current thread for a maximum timeout Returns true if lock acquired, false otherwise QMutex
bool tryLock(int timeout) QReadWriteLock
bool tryLockForRead(int timeout) bool tryLockForWrite(int timeout)
QSemaphore bool tryAcquire(int n, int timeout)
64
Examples
// wait for at most 1 second if (mutex.tryLock(1000)) { // got it ... } else { ... }
65
New in 4.3
Recursive write-locking in QReadWriteLock Thread can lockForWrite() multiple times
QThread::idealThreadCount() Returns number of CPU cores
QThreadStorage Refactored to allow an arbitrary number of instances Previously hard-coded to 256
66
New in 4.4 (tentative)
QThread no longer abstract run() is not pure virtual anymore Default implementation calls exec() Use QThread without subclassing Avoid thread affinity of QThread confusion
67
New in 4.4 (tentative)
Public atomic API QAtomicInt
Atomic operations on integers bool ref(), bool deref() Test-and-set, fetch-and-store, fetch-and-add
QAtomicPointer Type-safe atomic pointer operations Test-and-set, fetch-and-store, fetch-and-add
Explicit memory ordering semantics Relaxed, acquire, release, ordered
Feature test API
68
New in 4.4 (tentative)
Qt Concurrent Not discussed here Stay put, scheduled immediately after this presentation
69
Agenda
Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4
70
Thanks!
Any questions?
top related