Presentation is loading. Please wait.

Presentation is loading. Please wait.

Art of Multiprocessor Programming1 Concurrent Hashing Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified.

Similar presentations


Presentation on theme: "Art of Multiprocessor Programming1 Concurrent Hashing Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified."— Presentation transcript:

1 Art of Multiprocessor Programming1 Concurrent Hashing Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified by Rajeev Alur for CIS640 University of Pennsylvania

2 Art of Multiprocessor Programming22 Linked Lists Ways to make highly-concurrent list- based Sets: –Fine-grained locks –Optimistic synchronization –Lazy synchronization –Lock-free synchronization What’s missing?

3 Art of Multiprocessor Programming3 Linear-Time Set Methods Problem is –add(), remove(), contains() –Take time linear in set size We want –Constant-time methods –(at least, on average)

4 Art of Multiprocessor Programming44 Hashing Hash function –h: items  integers Uniformly distributed –Different item most likely have different hash values Java hashCode() method

5 Art of Multiprocessor Programming55 Sequential Hash Map 0 1 2 3 16 9 h(k) = k mod 4 2 Items buckets

6 Art of Multiprocessor Programming6 Add an Item 0 1 2 3 16 9 7 h(k) = k mod 4 3 Items

7 Art of Multiprocessor Programming77 Add Another: Collision 0 1 2 3 164 9 7 h(k) = k mod 4 4 Items

8 Art of Multiprocessor Programming88 More Collisions 0 1 2 3 164 9 715 h(k) = k mod 4 5 Items

9 Art of Multiprocessor Programming99 More Collisions 0 1 2 3 164 9 715 h(k) = k mod 4 5 Items Problem: buckets getting too long

10 Art of Multiprocessor Programming10 Resizing 0 1 2 3 164 9 715 4 5 6 7 Grow the array 5 Items h(k) = k mod 8

11 Art of Multiprocessor Programming11 5 Items Resizing 0 1 2 3 164 9 715 4 5 6 7 h(k) = k mod 8 Adjust hash function

12 Art of Multiprocessor Programming12 Resizing 0 1 2 3 16 9 715 h(4) = 0 mod 8 4 5 6 7 4 h(k) = k mod 8

13 Art of Multiprocessor Programming13 Resizing 0 1 2 3 16 4 9 715 4 5 6 7 h(k) = k mod 8 h(4) = 4 mod 8

14 Art of Multiprocessor Programming14 Resizing 0 1 2 3 16 4 9 715 4 5 6 7 h(k) = k mod 8 h(15) = 7 mod 8

15 Art of Multiprocessor Programming15 Resizing 0 1 2 3 16 4 9 4 5 6 7 h(k) = k mod 8 h(15) = 7 mod 8 157

16 Art of Multiprocessor Programming16 Hash Sets Implement a Set object –Collection of items, no duplicates –add(), remove(), contains() methods –You know the drill …

17 Art of Multiprocessor Programming17 Simple Hash Set public class SimpleHashSet { protected LockFreeList[] table; public SimpleHashSet(int capacity) { table = new LockFreeList[capacity]; for (int i = 0; i < capacity; i++) table[i] = new LockFreeList(); } …

18 Art of Multiprocessor Programming18 Fields public class SimpleHashSet { protected LockFreeList[] table; public SimpleHashSet(int capacity) { table = new LockFreeList[capacity]; for (int i = 0; i < capacity; i++) table[i] = new LockFreeList(); } … Array of lock-free lists

19 Art of Multiprocessor Programming19 Constructor public class SimpleHashSet { protected LockFreeList[] table; public SimpleHashSet(int capacity) { table = new LockFreeList[capacity]; for (int i = 0; i < capacity; i++) table[i] = new LockFreeList(); } … Initial size

20 Art of Multiprocessor Programming20 Constructor public class SimpleHashSet { protected LockFreeList[] table; public SimpleHashSet(int capacity) { table = new LockFreeList[capacity]; for (int i = 0; i < capacity; i++) table[i] = new LockFreeList(); } … Allocate memory

21 Art of Multiprocessor Programming21 Constructor public class SimpleHashSet { protected LockFreeList[] table; public SimpleHashSet(int capacity) { table = new LockFreeList[capacity]; for (int i = 0; i < capacity; i++) table[i] = new LockFreeList(); } … Initialization

22 Art of Multiprocessor Programming22 Add Method public boolean add(Object key) { int hash = key.hashCode() % table.length; return table[hash].add(key); }

23 Art of Multiprocessor Programming23 Add Method public boolean add(Object key) { int hash = key.hashCode() % table.length; return table[hash].add(key); } Use object hash code to pick a bucket

24 Art of Multiprocessor Programming24 Add Method public boolean add(Object key) { int hash = key.hashCode() % table.length; return table[hash].add(key); } Call bucket’s add() method

25 Art of Multiprocessor Programming25 No Brainer? We just saw a –Simple –Lock-free –Concurrent hash-based set implementation What’s not to like?

26 Art of Multiprocessor Programming26 No Brainer? We just saw a –Simple –Lock-free –Concurrent hash-based set implementation What’s not to like? We don’t know how to resize …

27 Art of Multiprocessor Programming27 Is Resizing Necessary? Constant-time method calls require –Constant-length buckets –Table size proportional to set size –As set grows, must be able to resize

28 Art of Multiprocessor Programming28 Set Method Mix Typical load –90% contains() –9% add () –1% remove() Growing is important Shrinking not so much

29 Art of Multiprocessor Programming29 When to Resize? Many reasonable policies. Here’s one. Pick a threshold on num of items in a bucket Global threshold –When ≥ ¼ buckets exceed this value Bucket threshold –When any bucket exceeds this value

30 Art of Multiprocessor Programming30 Coarse-Grained Locking Good parts –Simple –Hard to mess up Bad parts –Sequential bottleneck

31 Art of Multiprocessor Programming31 Fine-grained Locking 0 1 2 3 48 9 711 17 Each lock associated with one bucket

32 Art of Multiprocessor Programming32 Resize This Make sure table reference didn’t change between resize decision and lock acquisition 0 1 2 3 48 9 711 17 Acquire locks in ascending order

33 Art of Multiprocessor Programming33 Resize This 0 1 2 3 48 9 711 17 0 1 2 3 4 5 6 7 Allocate new super-sized table

34 Art of Multiprocessor Programming34 Resize This 0 1 2 3 9 7 48 17 0 1 2 3 4 5 6 7 8 4 9 7 11

35 Art of Multiprocessor Programming35 Resize This 0 1 2 3 0 1 2 3 4 5 6 7 8 4 9 17 7 11

36 Art of Multiprocessor Programming36 Resize This 0 1 2 3 0 1 2 3 4 5 6 7 8 4 9 17 7 11 Striped Locks: each lock now associated with two buckets

37 Art of Multiprocessor Programming37 Observations We grow the table, but not locks –Resizing lock array is tricky … We use sequential lists –Not LockFreeList lists –If we’re locking anyway, why pay?

38 Art of Multiprocessor Programming38 Fine-Grained Hash Set public class FGHashSet { protected RangeLock[] lock; protected List[] table; public FGHashSet(int capacity) { table = new List[capacity]; lock = new RangeLock[capacity]; for (int i = 0; i < capacity; i++) { lock[i] = new RangeLock(); table[i] = new LinkedList(); }} …

39 Art of Multiprocessor Programming39 Fine-Grained Hash Set public class FGHashSet { protected RangeLock[] lock; protected List[] table; public FGHashSet(int capacity) { table = new List[capacity]; lock = new RangeLock[capacity]; for (int i = 0; i < capacity; i++) { lock[i] = new RangeLock(); table[i] = new LinkedList(); }} … Array of locks

40 Art of Multiprocessor Programming40 Fine-Grained Hash Set public class FGHashSet { protected RangeLock[] lock; protected List[] table; public FGHashSet(int capacity) { table = new List[capacity]; lock = new RangeLock[capacity]; for (int i = 0; i < capacity; i++) { lock[i] = new RangeLock(); table[i] = new LinkedList(); }} … Array of buckets

41 Art of Multiprocessor Programming41 Fine-Grained Hash Set public class FGHashSet { protected RangeLock[] lock; protected List[] table; public FGHashSet(int capacity) { table = new List[capacity]; lock = new RangeLock[capacity]; for (int i = 0; i < capacity; i++) { lock[i] = new RangeLock(); table[i] = new LinkedList(); }} … Initially same number of locks and buckets

42 Art of Multiprocessor Programming42 The add() method public boolean add(Object key) { int keyHash = key.hashCode() % lock.length; synchronized (lock[keyHash]) { int tabHash = key.hashCode() % table.length; return table[tabHash].add(key); }

43 Art of Multiprocessor Programming43 Fine-Grained Locking public boolean add(Object key) { int keyHash = key.hashCode() % lock.length; synchronized (lock[keyHash]) { int tabHash = key.hashCode() % table.length; return table[tabHash].add(key); } Which lock?

44 Art of Multiprocessor Programming44 The add() method public boolean add(Object key) { int keyHash = key.hashCode() % lock.length; synchronized (lock[keyHash]) { int tabHash = key.hashCode() % table.length; return table[tabHash].add(key); } Acquire the lock

45 Art of Multiprocessor Programming45 Fine-Grained Locking public boolean add(Object key) { int keyHash = key.hashCode() % lock.length; synchronized (lock[keyHash]) { int tabHash = key.hashCode() % table.length; return table[tabHash].add(key); } Which bucket?

46 Art of Multiprocessor Programming46 The add() method public boolean add(Object key) { int keyHash = key.hashCode() % lock.length; synchronized (lock[keyHash]) { int tabHash = key.hashCode() % table.length; return table[tabHash].add(key); } Call that bucket’s add() method

47 Art of Multiprocessor Programming47 Fine-Grained Locking private void resize(int depth, List[] oldTab) { synchronized (lock[depth]) { if (oldTab == this.table){ int next = depth + 1; if (next < lock.length) resize (next, oldTab); else sequentialResize(); }}} resize() calls resize(0,this.table)

48 Art of Multiprocessor Programming48 Fine-Grained Locking private void resize(int depth, List[] oldTab) { synchronized (lock[depth]) { if (oldTab == this.table){ int next = depth + 1; if (next < lock.length) resize (next, oldTab); else sequentialResize(); }}} Acquire next lock

49 Art of Multiprocessor Programming49 Fine-Grained Locking private void resize(int depth, List[] oldTab) { synchronized (lock[depth]) { if (oldTab == this.table) { int next = depth + 1; if (next < lock.length) resize (next, oldTab); else sequentialResize(); }}} Check that no one else has resized

50 Art of Multiprocessor Programming50 Fine-Grained Locking private void resize(int depth, List[] oldTab) { synchronized (lock[depth]) { if (oldTab == this.table){ int next = depth + 1; if (next < lock.length) resize (next, oldTab); else sequentialResize(); }}} Recursively acquire next lock

51 Art of Multiprocessor Programming51 Fine-Grained Locking private void resize(int depth, List[] oldTab) { synchronized (lock[depth]) { if (oldTab == this.table){ int next = depth + 1; if (next < lock.length) resize (next, oldTab); else sequentialResize(); }}} Locks acquired, do the work

52 Art of Multiprocessor Programming52 Fine-Grained Locks We can resize the table But not the locks Debatable whether method calls are constant-time in presence of contention …

53 Art of Multiprocessor Programming53 Insight The contains() method –Does not modify any fields –Why should concurrent contains() calls conflict?

54 Art of Multiprocessor Programming54 Read/Write Locks public interface ReadWriteLock { Lock readLock(); Lock writeLock(); }

55 Art of Multiprocessor Programming55 Read/Write Locks public interface ReadWriteLock { Lock readLock(); Lock writeLock(); } Returns associated read lock

56 Art of Multiprocessor Programming56 Read/Write Locks public interface ReadWriteLock { Lock readLock(); Lock writeLock(); } Returns associated read lock Returns associated write lock

57 Art of Multiprocessor Programming57 Lock Safety Properties No thread may acquire the write lock –while any thread holds the write lock –or the read lock. No thread may acquire the read lock – while any thread holds the write lock. Concurrent read locks OK

58 Art of Multiprocessor Programming58 Read/Write Lock Satisfies safety properties –If readers > 0 then writer == false –If writer = true then readers == 0 Liveness? –Lots of readers … –Writers locked out?

59 Art of Multiprocessor Programming59 FIFO R/W Lock As soon as a writer requests a lock No more readers accepted Current readers “drain” from lock Writer gets in

60 Art of Multiprocessor Programming60 The Story So Far Resizing is the hard part Fine-grained locks –Striped locks cover a range (not resized) Read/Write locks –FIFO property needed

61 Art of Multiprocessor Programming61 Stop The World Resizing Resizing stops all concurrent operations What about an incremental resize? Must avoid locking the table A lock-free table + incremental resizing?

62 Art of Multiprocessor Programming62 Lock-Free Resizing Problem 0 1 2 3 48 9 715

63 Art of Multiprocessor Programming63 Lock-Free Resizing Problem 0 1 2 3 48 9 715 12 Need to extend table

64 Art of Multiprocessor Programming64 4 12 Lock-Free Resizing Problem 0 1 2 3 8 9 715 4 5 6 7 412 Need to extend table

65 Art of Multiprocessor Programming65 Lock-Free Resizing Problem 0 1 2 3 8 4 9 715 4 5 6 7 12 4

66 Art of Multiprocessor Programming66 Lock-Free Resizing Problem 0 1 2 3 9 715 4 5 6 7 12 to remove and then add even a single item single location CAS not enough 4 8 4 12 We need a new idea…

67 Art of Multiprocessor Programming67 Don’t move the items Move the buckets instead Keep all items in a single lock-free list Buckets become “shortcut pointers” into the list 16 4 9 7 15 0 1 2 3

68 Art of Multiprocessor Programming68 Recursive Split Ordering 0 0 4261537

69 Art of Multiprocessor Programming69 Recursive Split Ordering 0 1/2 1 0 4261537

70 Art of Multiprocessor Programming70 Recursive Split Ordering 0 1/2 1 1/43/4 2 3 0 4261537

71 Art of Multiprocessor Programming71 Recursive Split Ordering 0 1/2 1 1/43/4 2 3 0 4261537 List entries sorted in order that allows recursive splitting. How?

72 Art of Multiprocessor Programming72 Recursive Split Ordering 0 0 4261537

73 Art of Multiprocessor Programming73 Recursive Split Ordering 0 1 0 4261537 LSB 0 LSB 1 LSB = Least significant Bit

74 Art of Multiprocessor Programming74 Recursive Split Ordering 0 1 2 3 0 4261537 LSB 00LSB 10LSB 01LSB 11

75 Art of Multiprocessor Programming75 Split-Order If the table size is 2 i, –Bucket b contains keys k k = b (mod 2 i ) –bucket index consists of key's i LSBs

76 Art of Multiprocessor Programming76 When Table Splits Some keys stay –b = k mod(2 i+1 ) Some move –b+2 i = k mod(2 i+1 ) Determined by (i+1) st bit –Counting backwards Key must be accessible from both –Keys that will move must come later

77 Art of Multiprocessor Programming77 A Bit of Magic 0 4261537 Real keys:

78 Art of Multiprocessor Programming78 A Bit of Magic 0 4261537 Real keys: 0 1234567 Split-order: Real key 1 is in the 4 th location

79 Art of Multiprocessor Programming79 A Bit of Magic 0 4261537 Real keys: 0 1234567 Split-order: 000100010110001101011111 000001010011100101110111 Real key 1 is in 4 th location

80 Art of Multiprocessor Programming80 A Bit of Magic Real keys: Split-order: 000100010110001101011111 000001010011100101110111

81 Art of Multiprocessor Programming81 A Bit of Magic Real keys: Split-order: 000100010110001101011111 000001010011100101110111 Just reverse the order of the key bits

82 Art of Multiprocessor Programming82 Split Ordered Hashing 0 1 2 3 0 4261537 000001010011100101110111 Order according to reversed bits

83 Art of Multiprocessor Programming83 Parent Always Provides a Short Cut 0 1 2 3 0 4261537 search

84 Art of Multiprocessor Programming84 Sentinel Nodes 0 1 2 3 16 4 9 715 Problem: how to remove a node pointed by 2 sources using CAS

85 Art of Multiprocessor Programming85 Sentinel Nodes 0 1 2 3 16 4 9 715 3 Solution: use a Sentinel node for each bucket 0 1

86 Art of Multiprocessor Programming86 Sentinel vs Regular Keys Want sentinel key for i ordered –before all keys that hash to bucket i –after all keys that hash to bucket (i-1)

87 Art of Multiprocessor Programming87 Splitting a Bucket We can now split a bucket In a lock-free manner Using two CAS() calls...

88 Art of Multiprocessor Programming88 Initialization of Buckets 0 1 16 4 9 715 0 1

89 Art of Multiprocessor Programming89 Initialization of Buckets 0 1 2 3 16 4 9 715 0 1 3 Need to initialize bucket 3 to split bucket 1 3 in list but not connected to bucket yet Now 3 points to sentinel – bucket has been split

90 Art of Multiprocessor Programming90 Adding 10 0 1 2 3 16 4 9 37 0 1 2 10 = 2 mod 4 2 Must initialize bucket 2 Then can add 10

91 Art of Multiprocessor Programming91 Recursive Initialization 0 1 2 3 8 12 0 7 = 3 mod 4 To add 7 to the list 3 Must initialize bucket 3Must initialize bucket 1 = 1 mod 2 1 Could be log n depth But EXPECTED depth is constant

92 Art of Multiprocessor Programming92 Lock-Free List int makeRegularKey(int key) { return reverse(key | 0x80000000); } int makeSentinelKey(int key) { return reverse(key); }

93 Art of Multiprocessor Programming93 Lock-Free List int makeRegularKey(int key) { return reverse(key | 0x80000000); } int makeSentinelKey(int key) { return reverse(key); } Regular key: set high-order bit to 1 and reverse

94 Art of Multiprocessor Programming94 Lock-Free List int makeRegularKey(int key) { return reverse(key | 0x80000000); } int makeSentinelKey(int key) { return reverse(key); } Sentinel key: simply reverse (high-order bit is 0)

95 Art of Multiprocessor Programming95 Main List Lock-Free List from earlier class With some minor variations

96 Art of Multiprocessor Programming96 Lock-Free List public class LockFreeList { public boolean add(Object object, int key) {...} public boolean remove(int k) {...} public boolean contains(int k) {...} public LockFreeList(LockFreeList parent, int key) {...}; }

97 Art of Multiprocessor Programming97 Lock-Free List public class LockFreeList { public boolean add(Object object, int key) {...} public boolean remove(int k) {...} public boolean contains(int k) {...} public LockFreeList(LockFreeList parent, int key) {...}; } Change: add takes key argument

98 Art of Multiprocessor Programming98 Lock-Free List public class LockFreeList { public boolean add(Object object, int key) {...} public boolean remove(int k) {...} public boolean contains(int k) {...} public LockFreeList(LockFreeList parent, int key) {...}; } Inserts sentinel with key if not already present …

99 Art of Multiprocessor Programming99 Lock-Free List public class LockFreeList { public boolean add(Object object, int key) {...} public boolean remove(int k) {...} public boolean contains(int k) {...} public LockFreeList(LockFreeList parent, int key) {...}; } … returns new list starting with sentinel (shares with parent)

100 Art of Multiprocessor Programming100 Split-Ordered Set: Fields public class SOSet { protected LockFreeList[] table; protected AtomicInteger tableSize; protected AtomicInteger setSize; public SOSet(int capacity) { table = new LockFreeList[capacity]; table[0] = new LockFreeList(); tableSize = new AtomicInteger(2); setSize = new AtomicInteger(0); }

101 Art of Multiprocessor Programming101 Fields public class SOSet { protected LockFreeList[] table; protected AtomicInteger tableSize; protected AtomicInteger setSize; public SOSet(int capacity) { table = new LockFreeList[capacity]; table[0] = new LockFreeList(); tableSize = new AtomicInteger(2); setSize = new AtomicInteger(0); } For simplicity treat table as big array …

102 Art of Multiprocessor Programming102 Fields public class SOSet { protected LockFreeList[] table; protected AtomicInteger tableSize; protected AtomicInteger setSize; public SOSet(int capacity) { table = new LockFreeList[capacity]; table[0] = new LockFreeList(); tableSize = new AtomicInteger(2); setSize = new AtomicInteger(0); } In practice, want something that grows dynamically

103 Art of Multiprocessor Programming103 Fields public class SOSet { protected LockFreeList[] table; protected AtomicInteger tableSize; protected AtomicInteger setSize; public SOSet(int capacity) { table = new LockFreeList[capacity]; table[0] = new LockFreeList(); tableSize = new AtomicInteger(2); setSize = new AtomicInteger(0); } How much of table array are we actually using?

104 Art of Multiprocessor Programming104 Fields public class SOSet { protected LockFreeList[] table; protected AtomicInteger tableSize; protected AtomicInteger setSize; public SOSet(int capacity) { table = new LockFreeList[capacity]; table[0] = new LockFreeList(); tableSize = new AtomicInteger(2); setSize = new AtomicInteger(0); } Track set size so we know when to resize

105 Art of Multiprocessor Programming105 Fields public class SOSet { protected LockFreeList[] table; protected AtomicInteger tableSize; protected AtomicInteger setSize; public SOSet(int capacity) { table = new LockFreeList[capacity]; table[0] = new LockFreeList(); tableSize = new AtomicInteger(1); setSize = new AtomicInteger(0); } Initially use 1 bucket and size is zero

106 Art of Multiprocessor Programming106 Add() Method public boolean add(Object object) { int hash = object.hashCode(); int bucket = hash % tableSize.get(); int key = makeRegularKey(hash); LockFreeList list = getBucketList(bucket); if (!list.add(object, key)) return false; resizeCheck(); return true; }

107 Art of Multiprocessor Programming107 Add() Method public boolean add(Object object) { int hash = object.hashCode(); int bucket = hash % tableSize.get(); int key = makeRegularKey(hash); LockFreeList list = getBucketList(bucket); if (!list.add(object, key)) return false; resizeCheck(); return true; } Pick a bucket

108 Art of Multiprocessor Programming108 Add() Method public boolean add(Object object) { int hash = object.hashCode(); int bucket = hash % tableSize.get(); int key = makeRegularKey(hash); LockFreeList list = getBucketList(bucket); if (!list.add(object, key)) return false; resizeCheck(); return true; } Non-Sentinel split-ordered key

109 Art of Multiprocessor Programming109 Add() Method public boolean add(Object object) { int hash = object.hashCode(); int bucket = hash % tableSize.get(); int key = makeRegularKey(hash); LockFreeList list = getBucketList(bucket); if (!list.add(object, key)) return false; resizeCheck(); return true; } Get pointer to bucket’s sentinel, initializing if necessary

110 Art of Multiprocessor Programming110 Add() Method public boolean add(Object object) { int hash = object.hashCode(); int bucket = hash % tableSize.get(); int key = makeRegularKey(hash); LockFreeList list = getBucketList(bucket); if (!list.add(object, key)) return false; resizeCheck(); return true; } Call bucket’s add() method with reversed key

111 Art of Multiprocessor Programming111 Add() Method public boolean add(Object object) { int hash = object.hashCode(); int bucket = hash % tableSize.get(); int key = makeRegularKey(hash); LockFreeList list = getBucketList(bucket); if (!list.add(object, key)) return false; resizeCheck(); return true; } No change? We’re done.

112 Art of Multiprocessor Programming112 Add() Method public boolean add(Object object) { int hash = object.hashCode(); int bucket = hash % tableSize.get(); int key = makeRegularKey(hash); LockFreeList list = getBucketList(bucket); if (!list.add(object, key)) return false; resizeCheck(); return true; } Time to resize?

113 Art of Multiprocessor Programming113 Resize Divide set size by total number of buckets If quotient exceeds threshold –Double tableSize field –Up to fixed limit

114 Art of Multiprocessor Programming114 Initialize Buckets Buckets originally null If you find one, initialize it Go to bucket’s parent –Earlier nearby bucket –Recursively initialize if necessary Constant expected work

115 Art of Multiprocessor Programming115 Recall: Recursive Initialization 0 1 2 3 8 12 0 7 = 3 mod 4 To add 7 to the list 3 Must initialize bucket 3Must initialize bucket 1 = 1 mod 2 1 Could be log n depth But EXPECTED depth is constant

116 Art of Multiprocessor Programming116 Initialize Bucket void initializeBucket(int bucket) { int parent = getParent(bucket); if (table[parent] == null) initializeBucket(parent); int key = makeSentinelKey(bucket); LockFreeList list = new LockFreeList(table[parent], key); }

117 Art of Multiprocessor Programming117 Initialize Bucket void initializeBucket(int bucket) { int parent = getParent(bucket); if (table[parent] == null) initializeBucket(parent); int key = makeSentinelKey(bucket); LockFreeList list = new LockFreeList(table[parent], key); } Find parent, recursively initialize if needed

118 Art of Multiprocessor Programming118 Initialize Bucket void initializeBucket(int bucket) { int parent = getParent(bucket); if (table[parent] == null) initializeBucket(parent); int key = makeSentinelKey(bucket); LockFreeList list = new LockFreeList(table[parent], key); } Prepare key for new sentinel

119 Art of Multiprocessor Programming119 Initialize Bucket void initializeBucket(int bucket) { int parent = getParent(bucket); if (table[parent] == null) initializeBucket(parent); int key = makeSentinelKey(bucket); LockFreeList list = new LockFreeList(table[parent], key); } Insert sentinel if not present, and get back reference to rest of list

120 Art of Multiprocessor Programming120 Correctness Linearizable concurrent set implementation Theorem: O(1) expected time –No more than O(1) items expected between two dummy nodes on average –Lazy initialization causes at most O(1) expected recursion depth in initializeBucket()

121 Art of Multiprocessor Programming121 Summary Concurrent resizing is tricky Lock-based –Fine-grained –Read/write locks –Optimistic Lock-free –Builds on lock-free list


Download ppt "Art of Multiprocessor Programming1 Concurrent Hashing Companion slides for The Art of Multiprocessor Programming by Maurice Herlihy & Nir Shavit Modified."

Similar presentations


Ads by Google