devdays2007 - multi-threading in qt

70
Multi-threading in Qt Bradley T Hughes

Upload: aanvanbasten

Post on 18-Apr-2015

109 views

Category:

Documents


7 download

TRANSCRIPT

Page 1: DevDays2007 - Multi-Threading in Qt

Multi-threading in QtBradley T Hughes

Page 2: DevDays2007 - Multi-Threading in Qt

2

Introduction

Bradley T Hughes Joined Trolltech in May, 2000 Senior Software Engineer Team Lead for the Qt Platform Team Open Source Programmer

Page 3: DevDays2007 - Multi-Threading in Qt

3

Agenda

Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4

Page 4: DevDays2007 - Multi-Threading in Qt

4

Thread Support in Qt

What can I do with Qt? Platform independent multi-threading Start threads Synchronize threads Store per-thread data

Page 5: DevDays2007 - Multi-Threading in Qt

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

Page 6: DevDays2007 - Multi-Threading in Qt

6

Agenda

Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4

Page 7: DevDays2007 - Multi-Threading in Qt

7

Classes

QThread Abstract class

Must reimplement 'void run()' void start() bool wait(ulong timeout) void terminate() - DO NOT USE bool isFinished() bool isRunning()

Page 8: DevDays2007 - Multi-Threading in Qt

8

Classes

QThread QObject subclass

SIGNAL(started()) SIGNAL(finished()) SIGNAL(terminated())

Per-thread event loop int exec() SLOT(quit())

Page 9: DevDays2007 - Multi-Threading in Qt

9

Examples

class MyThread : public QThread{ Q_OBJECTpublic: void run() { // do some work }};

Page 10: DevDays2007 - Multi-Threading in Qt

10

Examples

void MyClass::startThread(){ myThread = new MyThread; connect(myThread, SIGNAL(finished()), SLOT(threadFinished())); thread->start();}

Page 11: DevDays2007 - Multi-Threading in Qt

11

Examples

void MyClass::threadFinished(){ // myThread is finished ...

// cleanup delete myThread; myThread = 0;}

Page 12: DevDays2007 - Multi-Threading in Qt

12

Classes

QMutex Mutual-exclusion primitive Recursive and non-recursive (default) modes void lock(), bool tryLock() void unlock()

Page 13: DevDays2007 - Multi-Threading in Qt

13

Examples

void MyQueue::queueNew() { // protect data, not code mutex.lock(); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity); mutex.unlock();}

Page 14: DevDays2007 - Multi-Threading in Qt

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()

Page 15: DevDays2007 - Multi-Threading in Qt

15

Examples

void MyQueue::queueNew(){ QMutexLocker locker(&mutex); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity);}

Page 16: DevDays2007 - Multi-Threading in Qt

16

Examples

void MyClass::complexFunction(){ QMutexLocker locker(&mutex); if (...) return; // unlocked try { ... } catch { ... throw; // unlocked }} // unlocked

Page 17: DevDays2007 - Multi-Threading in Qt

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()

Page 18: DevDays2007 - Multi-Threading in Qt

18

Examples

Entity *MyQueue::dequeue(){ QMutexLocker locker(&mutex); while (queue.isEmpty()) waitCondition.wait(&mutex); return queue.takeFirst();}

Page 19: DevDays2007 - Multi-Threading in Qt

19

Examples

void MyQueue::queueNew(){ QMutexLocker locker(&mutex); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity); waitCondition.wakeOne();}

Page 20: DevDays2007 - Multi-Threading in Qt

20

Classes

QSemaphore Simple counting semaphore Constructor initializes available resources void acquire(int), bool tryAcquire(int) void release(int) int available()

Page 21: DevDays2007 - Multi-Threading in Qt

21

Examples

void Producer::run(){ for(int i = 0; i < DataSize; ++i) { freeBytes.acquire(); buffer[i] = qrand()%4; usedBytes.release(); }}

Page 22: DevDays2007 - Multi-Threading in Qt

22

Examples

void Consumer::run(){ for(int i = 0; i < DataSize; ++i) { usedBytes.acquire(); file.write(buffer[i]); freeBytes.release(); }}

Page 23: DevDays2007 - Multi-Threading in Qt

23

Classes

QReadWriteLock Shared-exclusive lock Multiple readers, single writer void lockForRead(), bool tryLockForRead() void lockForWrite(), bool tryLockForWrite() void unlock()

Page 24: DevDays2007 - Multi-Threading in Qt

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;}

Page 25: DevDays2007 - Multi-Threading in Qt

25

Examples

void MyQueue::queueNew(){ readWriteLock.lockForWrite(); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity); readWriteLock.unlock();}

Page 26: DevDays2007 - Multi-Threading in Qt

26

Classes

QReadLocker and QWriteLocker RAII again This time on QReadWriteLock void unlock(), void relock() Starting with 4.2, also keeps state

Page 27: DevDays2007 - Multi-Threading in Qt

27

Examples

bool MyQueue::find(Entity *e){ QReadLocker locker(&lock); foreach (Entity *q, queue){ if (q == e) return true; } return false;}

Page 28: DevDays2007 - Multi-Threading in Qt

28

Examples

void MyQueue::queueNew(){ QWriteLocker locker(&lock); Entity *entity = cache.isEmpty() ? new Entity : cache.takeFirst(); queue.append(entity);}

Page 29: DevDays2007 - Multi-Threading in Qt

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

Page 30: DevDays2007 - Multi-Threading in Qt

30

Examples

QThreadStorage<Queue *> cache;

void MyQueue::done(Entity *e){ if (!cache.hasLocalData()) { Queue *q = new Queue; cache.setLocalData(q); } cache.localData()->append(e);}

Page 31: DevDays2007 - Multi-Threading in Qt

31

Examples

void MyQueue::queueNew(){ Queue *c = cache.localData(); Entity *entity = (!c || c->isEmpty()) ? new Entity : c->takeFirst(); QMutexLocker locker(&mutex); queue.append(entity);}

Page 32: DevDays2007 - Multi-Threading in Qt

32

Agenda

Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4

Page 33: DevDays2007 - Multi-Threading in Qt

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

Page 34: DevDays2007 - Multi-Threading in Qt

34

Pop Quiz

What is the thread affinity of QApplication?

Page 35: DevDays2007 - Multi-Threading in Qt

35

Pop Quiz

int main(int argc, char **argv){ QApplication app(argc, argv); qDebug() << app.thread();}

Page 36: DevDays2007 - Multi-Threading in Qt

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.

Page 37: DevDays2007 - Multi-Threading in Qt

37

Pop Quiz

What's the thread affinity of a QTimer created in a QThread::run() reimplementation?

Page 38: DevDays2007 - Multi-Threading in Qt

38

Pop Quiz

void MyThread::run(){ QTimer timer; qDebug() << timer.thread();}

Page 39: DevDays2007 - Multi-Threading in Qt

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.

Page 40: DevDays2007 - Multi-Threading in Qt

40

Pop Quiz

What is the affinity of a QThread instance?

Page 41: DevDays2007 - Multi-Threading in Qt

41

Pop Quiz

int main(int argc, char **argv){ QApplication app(argc, argv); QThread thread; qDebug() << thread.thread();}

Page 42: DevDays2007 - Multi-Threading in Qt

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...

Page 43: DevDays2007 - Multi-Threading in Qt

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...

Page 44: DevDays2007 - Multi-Threading in Qt

44

Examples

void MyObject::downloadFile(){ DlThread *thr = new DlThread; Downloader *dl = new Downloader;

// move 'dl' to another thread dl->moveToThread(thr);

...

Page 45: DevDays2007 - Multi-Threading in Qt

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();}

Page 46: DevDays2007 - Multi-Threading in Qt

46

Examples

class DlThread : public QThread{ Q_OBJECTpublic: void run() { exec(); }};

Page 47: DevDays2007 - Multi-Threading in Qt

47

Concepts

Posted events QApplication::postEvent() Schedules an event for delivery Different from sendEvent() Threads handle events for their objects

Page 48: DevDays2007 - Multi-Threading in Qt

48

Examples

void postAnEventTo(QObject *object){ QEvent *event = new QEvent(QEvent::User); QApplication::postEvent(object, event); // event not delivered yet!}

Page 49: DevDays2007 - Multi-Threading in Qt

49

Examples

bool sendAnEventTo(QObject *object){ QEvent event(QEvent::User); QApplication::sendEvent(object, &event); // event has been delivered return event.isAccepted();}

Page 50: DevDays2007 - Multi-Threading in Qt

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

Page 51: DevDays2007 - Multi-Threading in Qt

51

Examples

void MyObject::createSomeObject(){ SomeObject *receiver = new SomeObject; connect(this, SIGNAL(signal())), receiver, SLOT(slot())), Qt::QueuedConnection);}

void MyObject::emitSignal(){ emit signal(); }

Page 52: DevDays2007 - Multi-Threading in Qt

52

Examples

// Tip: call a slot by nameQMetaObject::invokeMethod( object, “slot”);

// Tip: pass an argumentQMetaObject::invokeMethod( object, “setText”, QString(“Hello World”));

Page 53: DevDays2007 - Multi-Threading in Qt

53

Examples

// Tip: but not right nowQMetaObject::invokeMethod( object, “setText”, Qt::QueuedConnection, QString(“Hello World”));

Page 54: DevDays2007 - Multi-Threading in Qt

54

Concepts

Implicit sharing Copy-on-write

All shared classes are implicit All use atomic reference counting

Page 55: DevDays2007 - Multi-Threading in Qt

55

Examples

void MyThread::run(){ QString string; forever { // implicit sharing in action string = readLargeFile(); // just pass a copy emit dataReady(string); }}

Page 56: DevDays2007 - Multi-Threading in Qt

56

Examples

// atomic ref count != thread-safe!QString string;

void MyThread::run(){ forever { // WRONG, cannot copy/modify // at the same time string = format(string); }}

Page 57: DevDays2007 - Multi-Threading in Qt

57

Examples

QMutex mutex;QString string;

void MyThread::run(){ forever { // RIGHT, protect shared data QMutexLocker locker(&mutex); string = format(string); }}

Page 58: DevDays2007 - Multi-Threading in Qt

58

Agenda

Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4

Page 59: DevDays2007 - Multi-Threading in Qt

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

Page 60: DevDays2007 - Multi-Threading in Qt

60

Examples

connect( sender, SIGNAL(signal()), receiver, SLOT(slot()), Qt::BlockingQueuedConnection);

QMetaObject::invokeMethod( object, “methodName”, Qt::BlockingQueuedConnection);

Page 61: DevDays2007 - Multi-Threading in Qt

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

Page 62: DevDays2007 - Multi-Threading in Qt

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

Page 63: DevDays2007 - Multi-Threading in Qt

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)

Page 64: DevDays2007 - Multi-Threading in Qt

64

Examples

// wait for at most 1 second if (mutex.tryLock(1000)) { // got it ... } else { ... }

Page 65: DevDays2007 - Multi-Threading in Qt

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

Page 66: DevDays2007 - Multi-Threading in Qt

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

Page 67: DevDays2007 - Multi-Threading in Qt

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

Page 68: DevDays2007 - Multi-Threading in Qt

68

New in 4.4 (tentative)

Qt Concurrent Not discussed here Stay put, scheduled immediately after this presentation

Page 69: DevDays2007 - Multi-Threading in Qt

69

Agenda

Introduction Thread Support Overview Classes Concepts New in 4.3 and 4.4

Page 70: DevDays2007 - Multi-Threading in Qt

70

Thanks!

Any questions?