Hazard Pointers

Hazard Pointers Hazard Pointers - Start

2017-07-29 80K 80 0 0

Hazard Pointers - Description

C. ++ . Memory Ordering Issues. Maged Michael. Facebook NY. Dagstuhl. , 21-25 November 2016. Maged . Michael. , Hazard Pointers: Safe Memory Reclamation for Lock-Free . Objects..  . IEEE Transactions on Parallel and Distributed Systems. ID: 574038 Download Presentation

Download Presentation

Hazard Pointers




Download Presentation - The PPT/PDF document "Hazard Pointers" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.



Presentations text content in Hazard Pointers

Slide1

Hazard PointersC++ Memory Ordering Issues

Maged Michael

Facebook NY

Dagstuhl

, 21-25 November 2016

Slide2

Maged Michael, Hazard Pointers: Safe Memory Reclamation for Lock-Free Objects. IEEE Transactions on Parallel and Distributed Systems. 15 (8): 491–504, June 2004.[P0233R2] Latest version of the proposal to the C++ Standard Committeehttp://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0233r2.pdfPrototype library under facebook/folly/experimentalhttps://github.com/facebook/folly/tree/master/folly/experimental/hazptr

References

Maged Michael - Hazard Pointers

2

Slide3

Problems

Slide4

Running Example: Wide CAS

4

Place wide data in a dynamic block

Wide CAS (compare and set) operates atomically on memory locations wider than the width of standard atomic primitives

u

X

atomically

if (X == u) X = v return true else return false

A common solution: copy-on-write

Updates replace the block

u

v

P

Wide

CAS

Maged Michael - Hazard Pointers

Slide5

class

WideCAS { class Node { T val_; ... }; atomic<Node*> s_ = {new Node()}; bool compareAndSet(T& u, T& v) { while (true) { Node* p = s_.load(); if (p->val_ != u) return false; Node* n = new Node(v); if (s_.compare_exchange_weak(p, n)) break; delete n; } delete p; return true; }};

Wide CAS Class

ABA Problem

Unsafe Memory Reclamation

Unsafe Memory Access

incorrect

Maged Michael - Hazard Pointers

5

Slide6

Unsafe Memory Reclamation

s_

u

A

w

B

1

Thread

i

reads pointer value A from

s_

Thread

i

accesses unmapped memory

3

Thread j sets s_ to B and frees A to OS

2

1

Node* p = s_.load(); if (p->val_ != u) ... Node* n = new Node(v); if (!s_.cas(p,n)) ... delete p; return true;

3

ACCESS VIOLATION

Example (Wide CAS)

returned to OS

Maged Michael - Hazard Pointers

6

Slide7

The ABA Problem

7

s_

u

A

w

B

1

Thread

i

reads

A

from

s_

Thread j sets s_ to B

Thread j reuses block A to hold value z

z

A

v

C

Thread j sets

s_

to A again

Thread i checks that s_ is equal to ACAS succeeds although s_->val_ == z != u

3

4

5

7

Thread i reads u from *A

2

1

Node* p = s_.load(); if (p->val_ != u) ... Node* n = new Node(v); if (!s_.cas(p,n)) ... delete p; return true;

7

2

6

Thread i allocates block C to hold value v

6

INCORRECT OUTCOME

Example

Maged Michael - Hazard Pointers

Slide8

Three levels of non-blocking progress:

An operation is wait-free, ifwhenever a thread executing the operation takes a finite number of steps,the operation must have completed,regardless of the actions/inaction of other threads.

An operation is lock-free, ifwhenever a thread executing the operation takes a finite number of steps,some operation must have completed,regardless of the actions/inaction of other threads.

An operation is obstruction-free, ifwhenever a thread executing the operation takes a finite number of steps alone,the operation must have completed,regardless of where the other threads stopped.

Non-Blocking Progress Guarantees

8

Maged Michael - Hazard Pointers

Slide9

Hazard Pointers

Slide10

Lock-free progress end-to-end

Features

Maged Michael - Hazard Pointers

10

Bounded to-be-reclaimed objects

No contention among readers

Can reclaim cycles

Unrestricted

reclamation

Slide11

A hazard pointer is a single-writer multi-reader pointer

Each hazard pointer has one owner (that can write to it)

By setting a hazard pointer to the address of an object, the owner is telling all threads: “if you remove this object after the last time I set this hazard pointer to this object don’t reclaim this object until the hazard pointer changes”

Protecting Objects

Maged Michael - Hazard Pointers

11

Slide12

1.

Read active hazard pointers. Keep a private copy of non-null valuesPrivate copy can be arranged in an efficient search structure e.g., O(1) expected lookup time

2. For each removed object, do a lookup in the private structureFound? Keep the object for a future scan of hazard pointersNot found? Reclaim the object

Reclaiming Objects

Maged Michael - Hazard Pointers

12

Slide13

class

WideCAS { class Node : hazptr_obj_base <Node> { T val_: ... }; atomic<Node*> s_ = {new Node()}; ... bool compareAndSet(T& u, T& v) { hazptr_owner<Node> hptr; do { Node* p = p_.load(); hptr.set(p); if (s_.load() != p)) continue; if (p->val_ != u) return false; // access hazard Node* n = new Node(v); if (s_.compare_exchange_weak(p, n)) break; // aba hazard delete n; } while (true); hptr.clear(); delete p; p.retire(); // reclaim when safe return true; }};

Wide CAS with Hazard Pointers

Maged Michael - Hazard Pointers

13

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

Slide14

Owns hazard pointersProtects objectsE.g., Traverses linked structures

Thread Roles

Maged Michael - Hazard Pointers

14

User

Makes objects unreachable

Prohibits the creation of new references to objects

E.g., Removes objects from data structures

Remover

Checks hazard pointers

Reclaims objects that are not protected by hazard pointers

Reclaimer

Slide15

Write hp := obj // no need for atomicityRead src == obj<safe use of obj>Write hp := !obj // no need for atomicity

Simplest Fully Concurrent Form of Hazard Pointers

Maged Michael - Hazard Pointers

15

User

Write

src

:= !

obj

Remover /

Reclaimer

Read

hp

!=

obj

//no

need for

atomicity

<reclaim

obj

>

Slide16

C++ Memory Ordering

Slide17

hp.store(obj)src.load() == obj<unsafe use of obj> (prohibited) // applicationhp.store(nullptr)

Three-Thread Pattern

Maged Michael - Hazard Pointers

17

User

src.store

(

other,maybe_weak

) // application

retired.insert

(

obj

)

Remover

retired.contains

(

obj

) // bulk

hp.load

() !=

obj

// bulk

<reclaim

obj

> // application

Reclaimer

Slide18

hp.store(1)src.load() == 0obj.load() == 1 (prohibited) // applicationhp.store(0)

Three-Thread Pattern

Maged Michael - Hazard Pointers

18

User

src.store

(1,maybe_weak) // application

retired.store

(1)

Remover

retired.load

() == 1 // bulk

hp.load

() == 0 // bulk

obj.store

(1,maybe_weak)

// application

Reclaimer

Slide19

hp.store(1,release)fence(seq_cst)src.load(relaxed) == 0obj.load() == 1 (prohibited) // applicationhp.store(0,release)

Three-Thread Pattern Memory Order Using Herd

Maged Michael - Hazard Pointers

19

User

src.store

(1,

maybe_weak

) // application

fence(

seq_cst

)

retired.store

(1,

relaxed

)

Remover

retired.load

(

relaxed

) == 1 // bulk

fence(

seq_cst

)

hp.load

(

relaxed

) == 0 // bulk

fence(acquire)

obj.store

(1,maybe_weak

) // application

Reclaimer

is this all the needed ordering?

Slide20

hp.store(obj)src.load() == obj<unsafe use of obj> (prohibited) // applicationhp.store(nullptr)

Four-Thread Pattern

Maged Michael - Hazard Pointers

20

User

src.store

(

other,maybe_weak

) // application

retired.insert

(

obj

)

Remover

retired.contains

(

obj

) // bulk

hp.load

() !=

obj

// bulk

<reclaim

obj

> // application

Reclaimer

<reallocate

obj

> // application

src.store

(

obj

, release) // application

Reuser

Slide21

hp.store(1)src.load() == 0obj.load() == 1 (prohibited) // applicationhp.store(0)

Four-Thread Pattern

Maged Michael - Hazard Pointers

21

User

src.store

(1,maybe_weak) // application

retired.store

(1)

Remover

retired.load

() == 1 // bulk

hp.load

() == 0 // bulk

obj.store

(1,maybe_weak)

// application

Reclaimer

obj.load

(

maybe_weak

) == 1 // application

obj.store

(0,maybe_weak) //

application

src.store

(0, release) // application

Reuser

Slide22

hp.store(1,release)fence(seq_cst)src.load(acquire) == 0obj.load() == 1 (prohibited) // applicationhp.store(0,release)

Four-Thread Pattern Memory Order Using Herd

Maged Michael - Hazard Pointers

22

User

src.store

(1,maybe_weak) // application

fence(

seq_cst

)

retired.store

(1

,relaxed

)

Remover

retired.load

(

,relaxed

) == 1 // bulk

fence(

seq_cst

)

hp.load

(

relaxed

) == 0 // bulk

fence(acquire)

obj.store

(1,maybe_weak)

// application

Reclaimer

obj.load

(

maybe_weak

) == 1 // application

obj.store

(0,maybe_weak) //

application

src.store

(0, release) // application

Reuser

Slide23

void set(T* ptr) { hp.store(release); fence(seq_cst);}bool try_protect(T* ptr,atomic<T*>& src) { set(ptr); return src.load(acquire) == ptr;}void clear() { hp.store(nullptr,release);}

Hazard Pointers Functions with Memory Order

Maged Michael - Hazard Pointers

23

User

void retire() {

fence(

seq_cst

);

retired.insert

(this);

}

Remover

Void

bulkReclaim

() {

List

objs

=

retired.extractAll

(); // bulk

fence(

seq_cst

);

Set h =

getHPVals

(); // bulk

fence(acquire)

reclaimUnmatched

(

objs,hps

); // bulk

}

Reclaimer

Slide24

Support for RMW operations is importantAutomatic generation of valid memory order combinations would be convenient

Summary of Experience

Maged Michael - Hazard Pointers

24

Slide25

Thank You

Slide26

Reference Countingshared_ptrSplit Reference Countingatomic_shared_ptrHazard PointersRCU(Read-Copy-Update)Unreclaimed objectsBounded (+chains)Bounded (+chains)BoundedUnboundedNon-blocking traversalBlocking (or lock-free w/ restrictions)lock-freeLock-freeWait-freeNon-blocking reclamationBlocking (or lock-free w/ restrictions)Lock-freeWait-free (lock-free with reclamation)BlockingContention among readersCan be very highCan be very highNo contentionNo contentionTraversal speedAtomic updates (~2)Several Atomic updates (~6)Store-load fenceNo or low overheadAutomatic reclamationYes (restricted if lock-free)YesNoNoCycle ReclamationNoNoYesYes

Safe Reclamation Solutions

26

Maged Michael - Hazard Pointers

Slide27

C++ Interface

Slide28

class

hazptr_domain;template <typename T, template Deleter = std::default_delete<T>>hazptr_obj_base;template <typename T> hazptr_owner;

Template Library Interface

Maged Michael - Hazard Pointers

28

Slide29

class

hazptr_domain { public: constexpr explicit hazptr_domain( std::pmr::memory_resource* /*C++17*/ = std::pmr::get_default_resource()) noexcept; ~hazptr_domain();};hazptr_domain& default_hazptr_domain();

hazptr_domain

Maged Michael - Hazard Pointers

29

Slide30

template

<typename T, template Deleter = std::default_delete<T>> hazptr_obj_base { public: void retire(hazptr_domain& domain = default_hazptr_domain(), Deleter reclaim = {});};

hazptr_obj_base

Maged Michael - Hazard Pointers

30

Slide31

template <

typename T> class hazptr_owner { public: /* Automatically acquire a hazard pointer */ explicit hazptr_owner( hazptr_domain& domain = default_hazptr_domain()); /* Automatically clear and release the owned hazard pointer */ ~hazptr_owner(); /** Hazard pointer operations */ /* Return true if successful in protecting the object. * Otherwise set ptr to src */ bool try_protect(T*& ptr, const std::atomic<T*>& src) noexcept; /* Get a protected reference from a source */ T* get_protected(const std::atomic<T*>& src) noexcept; /* Set the hazard pointer to ptr */ void set(const T* ptr) noexcept; /* Clear the hazard pointer */ void clear() noexcept;

hazptr_owner

Maged Michael - Hazard Pointers

31

Slide32

/* Swap ownership of hazard pointers with another hazptr_owner. * The owned hazard pointers remain unmodified during the swap and * continue to protect the respective objects that they were * protecting before the swap, if any. */ void swap(hazptr_owner<T>&) noexcept;};Template <typename T>void swap(hazptr_owner<T>&, hazptr_owner<T>&) noexcept;

hazptr_owner continued

Maged Michael - Hazard Pointers

32

Slide33

class

WideCAS { class Node : hazptr_obj_base <Node> { T val_: ... }; atomic<Node*> s_ = {new Node()}; ... bool compareAndSet(T& u, T& v) { do { Node* p = s_.load(); hazptr_owner<Node> hptr; if (!hptr.try_protect(p, s_)) continue; if (p->val_ != u) return false; // access hazard Node* n = new Node(v); if (s_.compare_exchange_weak(p, n)) break; // aba hazard delete n; // Automatically clear and release the owned hazard pointer. } while (true); p.retire(); return true; }};

Wide CAS with Hazard Pointers Template Interface

Maged Michael - Hazard Pointers

33

Slide34

bool contains(T

val) { // Acquire two hazard pointers for hand-over-hand traversal. hazptr_owner<Node> hptr_prev, hptr_curr; T elem; bool done = false; while (!done) { std::atomic<Node*>* prev = &head_; Node* curr = prev->load(); while (true) { if (!curr) { return false; } if (!hptr_curr.try_protect(curr, *prev)) break; Node* next = curr->next_.load(); // access hazard elem = curr->elem_; // access hazard if (prev->load() != curr) break; // aba hazard if (elem >= val) { done = true; break; } prev = &(curr->next_); curr = next; // hand-over-hand swap(hptr_curr, hptr_prev); } } return elem == val; // The hazard pointers are released automatically.}

Search Ordered Singly Linked List

Maged Michael - Hazard Pointers

34


About DocSlides
DocSlides allows users to easily upload and share presentations, PDF documents, and images.Share your documents with the world , watch,share and upload any time you want. How can you benefit from using DocSlides? DocSlides consists documents from individuals and organizations on topics ranging from technology and business to travel, health, and education. Find and search for what interests you, and learn from people and more. You can also download DocSlides to read or reference later.