Introduction to Lock-Free Programming Olivier Goffart 2014 About - - PowerPoint PPT Presentation

introduction to lock free programming
SMART_READER_LITE
LIVE PREVIEW

Introduction to Lock-Free Programming Olivier Goffart 2014 About - - PowerPoint PPT Presentation

Introduction to Lock-Free Programming Olivier Goffart 2014 About Me QStyleSheetStyle Itemviews Animation Framework QtScript (porting to JSC and V8) QObject, moc QML Debugger Modularisation . . . About Me Offering Qt help and services:


slide-1
SLIDE 1

Introduction to Lock-Free Programming

Olivier Goffart 2014

slide-2
SLIDE 2

About Me

QStyleSheetStyle Itemviews Animation Framework QtScript (porting to JSC and V8) QObject, moc QML Debugger Modularisation . . .

slide-3
SLIDE 3

About Me

Offering Qt help and services: Visit http://woboq.com C++ Code browser: http://code.woboq.org

slide-4
SLIDE 4

Goal of this presentation

Introduction to Lock-Free programming

slide-5
SLIDE 5

Singleton

1

class MySingleton {

2

static MySingleton *s_instance ;

3

static QMutex s_mutex;

4 5

public:

6 7

static MySingleton *instance ()

8

{

9

QMutexLocker lock (& s_mutex );

10

if (! s_instance ) {

11

s_instance = new MySingleton ();

12

}

13

return s_instance ;

14

}

15 16

// ....

17

};

slide-6
SLIDE 6

Singleton (wrong)

1

static MySingleton *instance ()

2

{

3

if (! s_instance ) {

4

QMutexLocker lock (& s_mutex );

5

if (! s_instance ) {

6

s_instance = new MySingleton ();

7

}

8

}

9

return s_instance ;

10

}

slide-7
SLIDE 7

Computer architecture

Compiler re-order CPU out of order execution Caches, Write buffers

slide-8
SLIDE 8

Singleton (Better)

1

class MySingleton {

2

static QAtomicPointer <MySingleton > s_instance;

3

static QMutex s_mutex;

4

public:

5

static MySingleton *instance ()

6

{

7

MySingleton *inst = s_instance . loadAcquire ();

8

if (! inst) {

9

QMutexLocker lck (& s_mutex );

10

if (! s_instance .load ()) { // relaxed

11

inst = new MySingleton ();

12

s_instance . storeRelease (inst );

13

}

14

}

15

return inst;

16

}

17

};

slide-9
SLIDE 9

Singleton (Best)

1

static MySingleton *instance ()

2

{

3

static MySingleton inst;

4

return &inst;

5

}

slide-10
SLIDE 10

Singleton (Best)

1

static MySingleton *instance ()

2

{

3

static MySingleton inst;

4

return &inst;

5

}

See also: Q GLOBAL STATIC

slide-11
SLIDE 11

C++11 Memory model

C++98

No mentions of threads.

The compiler is allowed to do any optimisation that is consistant to a single thread.

slide-12
SLIDE 12

C++11 Memory model

C++98

No mentions of threads.

The compiler is allowed to do any optimisation that is consistant to a single thread.

C++11 Defines race condition Restricts what kind of optimisation the compiler is allowed to do in regards to threading. std::atomic , std::thread, std::mutex

slide-13
SLIDE 13

C++11 Memory model

C++11 §1.10

  • 21. The execution of a program contains a data race if it contains two

conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.

slide-14
SLIDE 14

Lock-Free programming

slide-15
SLIDE 15

What’s wrong with mutexes?

slide-16
SLIDE 16

What’s wrong with mutexes?

All threads have to wait if a thread holding a lock is descheduled. More context switches waste CPU time. For real-time applications: priority inversion, unsafe in interrupts handlers, convoying.

slide-17
SLIDE 17

Lock-free algorithms

Sometimes faster No risks of deadlock, even if a thread is terminated/killed More difficult to design and understand

slide-18
SLIDE 18

Lock-free algorithms

Sometimes faster No risks of deadlock, even if a thread is terminated/killed More difficult to design and understand, but also fun

slide-19
SLIDE 19

QAtomicInt/QAtomicPointer

API testAndSet fetchAndStore fetchAndAdd Memory Ordering Ordered Acquire Release Relaxed Mix and Match

1

bool QAtomicInt :: testAndSetAcquire (int expectedValue ,

2

int newValue)

3

int QAtomicInt :: fetchAndAddOrdered (int valueToAdd )

4

T *QAtomicPointer <T >:: fetchAndStoreRelaxed (T *newValue)

slide-20
SLIDE 20

Fetch and Store

1

T *QAtomicPointer <T >:: fetchAndStore ...(T *newValue)

2

{

3

T *oldValue = _q_value;

4

_q_value = newValue;

5

return

  • ldValue;

6

}

slide-21
SLIDE 21

Fetch and Add

1

int QAtomicInt :: fetchAndAdd ...( int valueToAdd )

2

{

3

int

  • ldValue = _q_value;

4

_q_value += valueToAdd ;

5

return

  • ldValue;

6

}

slide-22
SLIDE 22

Test and Set

1

bool QAtomicInt :: testAndSet ...( int expectedValue ,

2

int newValue)

3

{

4

if (_q_value != expectedValue )

5

return false;

6

_q_value = newValue;

7

return true;

8

}

slide-23
SLIDE 23

Memory ordering

Acquire Memory access following the atomic

  • peration may not be re-ordered

before that operation. Ordered Same Acquire and Release combined: operations may not be re-ordered Release Memory access before the atomic

  • peration may not be re-ordered

after that operation. Relaxed Operations may be re-ordered before or after.

slide-24
SLIDE 24

Singleton (Lock-free)

1

class MySingleton {

2

static QAtomicPointer <MySingleton > s_instance;

3 4

public:

5

static MySingleton *instance ()

6

{

7

MySingleton *inst = s_instance . loadAcquire ();

8

if (! inst) {

9

inst = new MySingleton ();

10

if (! s_instance . testAndSetRelease (0, inst )) {

11

delete inst;

12

inst = s_instance. loadAcquire ();

13

}

14

}

15

return inst;

16

}

17

};

slide-25
SLIDE 25

Lock-Free Stack

slide-26
SLIDE 26

Lock-Free Stack (Push)

slide-27
SLIDE 27

Lock-Free Stack (Push)

slide-28
SLIDE 28

Lock-Free Stack (Push)

slide-29
SLIDE 29

Lock-Free Stack (Push)

slide-30
SLIDE 30

Lock-Free Stack (Push)

slide-31
SLIDE 31

Lock-Free Stack (Push)

slide-32
SLIDE 32

Lock-free stack

1

struct Stack {

2

QAtomicPointer <Node > head;

3

void push(Node *n) {

4

do {

5

n->next = head. loadAcquire ();

6

} while (! head. testAndSetOrdered (n->next , n));

7

}

8

// ...

9

};

slide-33
SLIDE 33

Lock-Free Stack (Pop)

slide-34
SLIDE 34

Lock-Free Stack (Pop)

slide-35
SLIDE 35

Lock-free stack Pop (wrong)

1

struct Stack {

2

QAtomicPointer <Node > head;

3

// ...

4

Node *pop () {

5

Node *n;

6

do {

7

n = head. loadAcquire ();

8

} while(n && !head. testAndSetOrdered (n, n->next ));

9

return n;

10

}

11

};

slide-36
SLIDE 36

ABA Problem

slide-37
SLIDE 37
slide-38
SLIDE 38
slide-39
SLIDE 39
slide-40
SLIDE 40
slide-41
SLIDE 41
slide-42
SLIDE 42

ABA Problem

Solutions

slide-43
SLIDE 43

ABA Problem

Solutions Add a serial number Multiple words compare and swap Garbage collector / Reference count Hazard pointers

slide-44
SLIDE 44

Example in Qt

Reference counting QMutex Q GLOBAL STATIC Allocation of timer ids . . .

slide-45
SLIDE 45

Other examples

RCU (Read-copy-update) Multiple words compare and swap. Transactional memory

slide-46
SLIDE 46

Transactional memory

In the Future... (N3718) :

1

void push(Node *n) {

2

transaction_atomic {

3

n->next = head;

4

head = n;

5

}

6

}

7 8

Node *pop () {

9

Node *n;

10

transaction_atomic {

11

n = head;

12

if (n)

13

head = n->next;

14

}

15

return n;

16

}

slide-47
SLIDE 47

Conclusion

Use mutexes. Profile.

slide-48
SLIDE 48

The END

Questions

slide-49
SLIDE 49

The END

Questions

  • livier@woboq.com

Visit http://woboq.com. Read More: http://woboq.com/blog/introduction-to-lockfree-programming.html, http://woboq.com/blog/internals-of-qmutex-in-qt5.html