enhancing with multi threading

Upload: rapo1

Post on 14-Apr-2018

228 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/30/2019 Enhancing With Multi Threading

    1/38

    1

    Enhancing your Qt application with

    multiple threads

    Thiago Macieira

    Qt Developer Days 2008

  • 7/30/2019 Enhancing With Multi Threading

    2/38

    2

    Who am I?

    Senior Software Engineer at Qt Software / Nokia

    Degrees in Engineering and an MBA

    Almost 2 years with the company

    Part of the Core Team

    Work mostly with Networking, I/O, IPC, Threading, Tool Classes

    Other official duties:

    Liaison to the KDE Community

    Release Manager for Qt

  • 7/30/2019 Enhancing With Multi Threading

    3/38

    API, do's and don'tsAPI, do's and don'ts

    Evolution of threading in QtEvolution of threading in Qt

    IntroductionIntroduction

    Agenda

  • 7/30/2019 Enhancing With Multi Threading

    4/38

    API, do's and don'ts

    Evolution of threading in Qt

    IntroductionIntroduction

    Agenda

  • 7/30/2019 Enhancing With Multi Threading

    5/385

    General recommendations

    In general, people advise against threads

    And give many reasons why

    Threads do make the program more complex

    If your problem doesn't require threads, you don't have to use it

    Threads are for people who

    can't program a statemachine

    -- Alan Cox

  • 7/30/2019 Enhancing With Multi Threading

    6/38

    6

    Multi-core hardware... ?

    Desktop processors are usually multi-core now

    Dual cores, quad cores, dual quad cores, etc.

    (This laptop is dual core)

    Embedded hardware to follow suit very soon

  • 7/30/2019 Enhancing With Multi Threading

    7/38

    7

    ... Threaded software !

    To use all cores, you need threads

    To use threads, you need to identify tasks

    Task 3

    Task 2

    Task 1

  • 7/30/2019 Enhancing With Multi Threading

    8/38

    8

    What can you use threads for?

  • 7/30/2019 Enhancing With Multi Threading

    9/38

    9

    What can you use threads for?

    Time-consuming tasks

    Blocking operations

    Parallelising independent operations

    More...

  • 7/30/2019 Enhancing With Multi Threading

    10/38

    API, do's and don'ts

    Evolution of threading in QtEvolution of threading in Qt

    Introduction

    Agenda

  • 7/30/2019 Enhancing With Multi Threading

    11/38

    11

    In the beginning, there was nothing...

    Qt 1.x had no support for threading

    Qt 2.x had QThread, but not by default

    Qt 3.x had QThread by default

  • 7/30/2019 Enhancing With Multi Threading

    12/38

    12

    Qt 4.0 made threads first-class citizens

    Tool classes reentrant

    Thread-safe atomic detaching

    Event loops in auxiliary threads

    Cross-thread signal-slot connections

  • 7/30/2019 Enhancing With Multi Threading

    13/38

    13

    Cross-thread signal-slot connection

    Signals delivered immediately (DirectConnection)

    Or delivered later (QueuedConnection)

    Qt copies the arguments (QVariant)

    Posts an event to receiver object

    Events were already thread-safe

    Qt 4.3: BlockingQueuedConnection

  • 7/30/2019 Enhancing With Multi Threading

    14/38

    14

    Qt 4.4 brought threading to a new level

    Basic atomic operations

    New classes abstracting thread manipulation

    QtConcurrent

    Painting from multiple threads

    Thread-safe text rendering on X11

    Thread-safe rich-text and SVG support

  • 7/30/2019 Enhancing With Multi Threading

    15/38

    API, do's and don'tsAPI, do's and don'ts

    Evolution of threading in Qt

    Introduction

    Agenda

  • 7/30/2019 Enhancing With Multi Threading

    16/38

    API, do's and don'tsAPI, do's and don'ts

    Evolution of threading in Qt

    Introduction

    Threads & ConcurrentLocking & Atomic

    Agenda

  • 7/30/2019 Enhancing With Multi Threading

    17/38

    17

    Things to remember about QThread

    The QThread object is not in that thread

    Think of QThread as a manager object

    Constructor is run in another thread

    Be careful with signals and slots

    Event loop is not automatic To receive signals in that thread, you have to call exec()

  • 7/30/2019 Enhancing With Multi Threading

    18/38

    18

    The basic: starting a thread

    classMyThread: publicQThread

    {

    protected: voidrun()

    {// thread code here

    }};

    voidsomewhereElse()

    {

    MyThread *thr =newMyThread;

    thr->start();

    }

  • 7/30/2019 Enhancing With Multi Threading

    19/38

    19

    What if you need a thread, any thread?

    You don't need the thread running all of the time

    You just have a task that has to be run

    classMyTask: publicQRunnable

    {

    protected: voidrun()

    {// task code here

    }};

    QThreadPool *threadPool;

    voidsomewhereElse()

    { MyTask *task =

    newMyTask;threadPool->start(task);

    }

  • 7/30/2019 Enhancing With Multi Threading

    20/38

    20

    QThread vs. QRunnable

    QThread derives from QObject

    Signals and slots

    QObject is heavy

    Cost of creating a thread

    Existed since Qt 2.x

    QRunnable has no base class

    No signals or slots

    Light-weight

    Runs on any free thread

    New in Qt 4.4

  • 7/30/2019 Enhancing With Multi Threading

    21/38

    21

    What if you just need to run a function?

    The function already exists

    But no QThread or QRunnable exists for it

    intmyFunction()

    { // task code here

    return 42;}

    voidsomewhereElse()

    {

    QFuture result = QtConcurrent::run(myFunction);

    // do some other work

    result.waitForFinished();}

  • 7/30/2019 Enhancing With Multi Threading

    22/38

  • 7/30/2019 Enhancing With Multi Threading

    23/38

    23

    QFuture's family

    Multiple QFuture can be combined in a QFutureSynchronizer

    For non-blocking synchronisation, there is QFutureWatcher

    Signals and slots

    QFuture f1 = ...;

    QFuture f2 = ...;

    QFutureSynchronizer sync;

    sync.addFuture(f1);

    sync.addFuture(f2);sync.waitForFinished();

    QFuture future = ...;QFutureWatcher watcher;

    watcher.setFuture(future);

    connect(&watcher,

    SIGNAL(finished()),

    this, SLOT(slotFinished()));

  • 7/30/2019 Enhancing With Multi Threading

    24/38

    24

    Passing an argument?

    QtConcurrent allows you to pass arguments to functions

    intmyTask(QString val)

    { // task code here

    return val.toInt();}

    voidsomewhereElse()

    { QFuture result =

    QtConcurrent::run(myTask, 42);}

  • 7/30/2019 Enhancing With Multi Threading

    25/38

    Run the function once for every entry in the sequence

    voidmyTask(int id)

    {// task code here

    }

    voidsomewhereElse(QList ids)

    {

    QFuture result = QtConcurrent::mapped(ids,

    myTask);

    }

    Passing an argument from a list?

  • 7/30/2019 Enhancing With Multi Threading

    26/38

    26

    Retrieving returned values

    Each functions result is stored in QFuture

    Call results() to obtain a QList with the values

    qlonglongmyTask(int id)

    {// task code here

    return id;

    }

    QList

    somewhereElse(QList ids)

    {

    QFuture future = QtConcurrent::mapped(ids,

    myTask);

    future.waitForFinished();

    return future.results()

    }

  • 7/30/2019 Enhancing With Multi Threading

    27/38

    API, do's and don'tsAPI, do's and don'ts

    Evolution of threading in Qt

    Introduction

    Threads & ConcurrentLocking & Atomic

    Agenda

  • 7/30/2019 Enhancing With Multi Threading

    28/38

    28

    Global data: locking

    Access to global data must be protected

    static MyObjectglobalData;

    staticQMutexmutex;

    voidtask1()

    {mutex.lock();

    // use globalData

    mutex.unlock();}

    voidtask2(){ QMutexLocker locker(&mutex);

    // use globalData

    }

  • 7/30/2019 Enhancing With Multi Threading

    29/38

    29

    More refined locking

    Depends on the type of access

    static MyObjectglobalData;

    staticQReadWriteLockmutex;

    voidtask1()

    {mutex.lockForRead();

    // use globalData

    mutex.unlock();}

    voidtask2()

    {mutex.lockForWrite();

    // modify globalData

    mutex.unlock();}

  • 7/30/2019 Enhancing With Multi Threading

    30/38

    30

    static QAtomicIntcounter;

    Sometimes no locking is needed

    If the operation can be atomic

    voidtask1()

    {

    intid = counter.fetchAndAddRelaxed(1);

    // operation

    counter

    .fetchAndAddRelaxed(-1);

    }

    voidtask2(){

    int currentCount = counter;

    qDebug()

  • 7/30/2019 Enhancing With Multi Threading

    31/38

    31

    static volatile intcounter;static intcounter;

    Why can't you use int?

    Operations on small integer types are atomic

    voidtask1()

    {

    intid = ++counter;

    // operation

    --counter;

    }

    voidtask2(){

    int currentCount = counter;

    qDebug()

  • 7/30/2019 Enhancing With Multi Threading

    32/38

    32

    static volatile intcounter;

    Why can't you use int?

    Operations on small integer types are atomic

    voidtask1()

    {

    intid = ++counter;

    // operation

    --counter;

    }

    voidtask2(){

    int currentCount = counter;

    qDebug()

  • 7/30/2019 Enhancing With Multi Threading

    33/38

    33

    QAtomicInt & QAtomicPointer

    Atomic operations supported:

    Test-and-set (a.k.a. compare-and-exchange)

    Fetch-and-store (a.k.a. exchange)

    Fetch-and-add

    Each operation supports 4 memory ordering semantics

    If the hardware supports it

    QAtomicInt is very useful for reference counting

  • 7/30/2019 Enhancing With Multi Threading

    34/38

    34

    QAtomic feature testing

    Level of functionality varies according to hardware

    Tests at compile time (macros)

    or at run-time (static functions)

    Operations can be:

    Native or emulated Wait-free or looping

  • 7/30/2019 Enhancing With Multi Threading

    35/38

    35

    Even for slightly complex structures

    The pop() function is left as an exercise for the reader

    class LockFreeStack

    {

    QAtomicPointer stack;

    public:

    voidpush(MyType *t)

    { do {

    t->next = stack;

    } while (!stack.testAndSetRelease(t->next, t));

    }

    };

    d

  • 7/30/2019 Enhancing With Multi Threading

    36/38

    SummarySummary

    Agenda

    S i d ' d h d

  • 7/30/2019 Enhancing With Multi Threading

    37/38

    37

    Sometimes you don't need threads

    Analyse your problem

    Can it be done without threads?

    For example, signals and slots

    State machine!

    U i th d h ld b

  • 7/30/2019 Enhancing With Multi Threading

    38/38

    38

    Using threads should be easy

    We give you all the rope you need and a little more

    API is there and constantly being improved

    We're probably not done yet...

    Just because you can, itdoesn't mean you should.