devdays2007 - multi-threading in qt

Post on 18-Apr-2015

117 Views

Category:

Documents

7 Downloads

Preview:

Click to see full reader

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