Art of Multiprocessor Programming 答案 ch9
来源:互联网 发布:unity3d 雷电特效 编辑:程序博客网 时间:2024/04/30 12:03
100. 将add()方法的 if(cur.key == key) return false去掉,改为找到 pred.key <= key && curr.key > key为插入的位置。remove()方法和contains()方法都是找到任意一个key == key时结束。
101. 所有的锁都按照升序获得,不会有循环,所以无死锁。
102. 当线程拥有pred.lock和curr.lock的时候,与这2个节点无关的操作并行操作,结果与这个add()方法无关,可以在串行化的历史中任意安排这2个操作的顺序;同时与这2个节点相关的操作,包括在pred后插入节点,删除pred和删除curr都将在获得2个锁的时候串行执行。这是add方法的可线性化点。
103. 没有对获得锁的循环。
104. 只要有pred和curr的关系不断变化就可以。比如说当前节点 head--> ... --> A --> B--> ... --> tail ; Threada想要remove B, Threadb不断在AB之间插入节点:
Ta.pred = A, Ta.curr = B; ==> Tb.pred = A, Tb.curr = B; Tb.pred.lock(), Tb.curr.lock(); ==> Tb inserts A1 ==> A-->A1-->B
==> Ta.pred.lock(), Ta.curr.lock() ==> Ta.validate ==> Ta.pred.next (A.next) != Ta.curr (B) ==> Ta tries remove again.
==> Tb inserts A2 ==> Ta failed ==> ...
或者重复的插入和删除:
Ta.pred = A, Ta.curr = B ==> Tb.pred = A, Tb.curr = B; Tb.pred.lock(), Tb.curr.lock() ==> Tb inserts A1 ==> A-->A1-->B
==> Ta.pred.lock(), Ta.curr.lock() ==> Ta.validate ==> Ta.pred.next != Ta.curr ==> Ta tries remove again.
==> Ta.pred = A1, Ta.curr = B; Tb.pred = A, Tb.curr = A1; Tb.pred.lock, Tb.curr.lock; ==> Tb.remove(curr) ==> A-->B
==> Ta.pred.lock, Ta.curr.lock ==> Ta.validate ==> Ta.pred not reachable ==> Ta tries remove again
==> Repeat
105.
public boolean contains(T item) { Node last = null, pred = null, curr = null; int key = item.hashCode(); head.lock(); try { pred = head; curr = pred.next; curr.lock(); try { while (curr.key < key) { pred.unlock(); pred = curr; curr = curr.next; curr.lock(); } return (curr.key == key); } finally { curr.unlock(); } } finally { pred.unlock(); }
106. 如果只有add交换顺序,remove不交换,会死锁。如果remove也交换,因为validation总是在获得2个锁之后,则算法仍然正确。
107. 如果pred可达,则它肯定能达到tail。
否则,可以用归纳法证明如果predA != null, 而且predA不可达,则predA所在的list一定能够达到一个可达的并能够达到Tail的节点(包括tail)。
当pred最开始从list删除的时候,因为有curr.lock(此时curr = predA),所以被删除的predA肯定有predA.next可达。
假设predA不可达,根据假设它所在的list一定能够达到一个可达的而且能够到达tail的节点(R);因为不可能对不可达的节点进行操作,所以增加节点并不会改变这个性质。如果删除节点R, 根据上面的证明,R一定有R-->R.next-->...-->tail ==〉predA --> ... --> R -->R.next --> ... --> tail
108. 常规的锁法之所以需要2个锁,是因为要确定pred->curr的关系,即确保pred->next在add/remove操作过程中不会改变。因为add操作只涉及到pred->next和一个将成为pred->next的新节点,所以add之需要锁pred。具体来说,考虑下面的case:
- ThreadA.add && ThreadB.add。ThreadA.pred.lock ==> ThreadB waiting for pred.lock ==> ThreadA.pred.next = new, new->next = ThreadA.curr ==> ThreadB.pred.lock() ==> ThreadB.valiation ==> Thread.B.pred.next != ThreadB.curr。
- ThreadA.add && ThreadB.remove(pred)。ThreadA.pred.lock ==> ThreadB.pred.pred.lock(), ThreadB.pred waiting for lock ==> ThreadA.pred.next = new, Thread.new.next = curr ==> ThreadB.pred.lock() ==> ThreadB.pred.pred.next = new
- ThreadA.add && ThreadB.remove(pred)。ThreadB.pred.pred.lock(), ThreadB.pred.lock() ==> ThreadA.pred waiting for lock ==> ThreadB.pred.pred.next = ThreadB.cur; ==> ThreadA.pred.lock() ==> ThreadA.validate ==> pred is not reachable
- ThreadA.add && ThreadB.remove(curr)。ThreadA.pred.lock ==> ThreadB.pred waiting for lock ==> ThreadA.pred.next = new, ThreadA.pred.next.next = ThreadA.cur; ==> ThreadB.pred.lock() ==> ThreadB.validate ==> ThreadB.pred.next != ThreadB.cur
- ThreadA.add && ThreadB.remove(curr)。ThreadB.pred.lock(), ThreadB.cur.lock() ==> ThreadA.pred waiting for lock ==> ThreadB.pred.next = ThreadB.cur.next ==> ThreadA.pred.lock() ==> ThreadA.validate ==> ThreadA.pred.next != ThreadA.curr
package p117;/* * LockFreeList.java * * Created on January 4, 2006, 2:41 PM * * From "Multiprocessor Synchronization and Concurrent Data Structures", * by Maurice Herlihy and Nir Shavit. * Copyright 2006 Elsevier Inc. All rights reserved. */import java.util.concurrent.atomic.AtomicMarkableReference;/** * Lock-free List based on M. Michael's algorithm. * @param T Item type. * @author Maurice Herlihy */public class LockFreeList<T> { /** * First list node */ Node head; /** * Constructor */ public LockFreeList() { this.head = new Node(Integer.MIN_VALUE); Node tail = new Node(Integer.MAX_VALUE); while (!head.next.compareAndSet(null, tail, false, false)); } /** * Add an element. * @param item element to add * @return true iff element was not there already *///fulltopic: Adjusted to reuse marked node public boolean add(T item) { int key = item.hashCode();Node node = null; while (true) { // find predecessor and curren entries Window window = find(head, key); Node pred = window.pred, curr = window.curr; // is the key present? if (curr.key == key) { return false; } else { // splice in new node if(node == null) { if(window.reuseNode != null) { node = window.reuseNode; node.item = item; }else { node = new Node(item); } }node.next = new AtomicMarkableReference<LockFreeList<T>.Node>(curr, false); if (pred.next.compareAndSet(curr, node, false, false)) { return true; } } } } /** * Remove an element. * @param item element to remove * @return true iff element was present */ public boolean remove(T item) { int key = item.hashCode(); boolean snip; while (true) { // find predecessor and curren entries Window window = find(head, key); Node pred = window.pred, curr = window.curr; // is the key present? if (curr.key != key) { return false; } else { // snip out matching node Node succ = curr.next.getReference(); snip = curr.next.attemptMark(succ, true); if (!snip) continue; pred.next.compareAndSet(curr, succ, false, false); return true; } } } /** * Test whether element is present * @param item element to test * @return true iff element is present */ public boolean contains(T item) { int key = item.hashCode(); // find predecessor and curren entries Window window = find(head, key); Node curr = window.curr; return (curr.key == key); } /** * list node */ private class Node { /** * actual item */ T item; /** * item's hash code */ int key; /** * next node in list */ AtomicMarkableReference<Node> next; /** * Constructor for usual node * @param item element in list */ Node(T item) { // usual constructor this.item = item; this.key = item.hashCode(); this.next = new AtomicMarkableReference<Node>(null, false); } /** * Constructor for sentinel node * @param key should be min or max int value */ Node(int key) { // sentinel constructor this.item = null; this.key = key; this.next = new AtomicMarkableReference<Node>(null, false); } } /** * Pair of adjacent list entries. */ class Window { /** * Earlier node. */ public Node pred; /** * Later node. */ public Node curr; public Node reuseNode; /** * Constructor. */ Window(Node pred, Node curr) { this.pred = pred; this.curr = curr; } //fulltopic: Set userNdoe Window(Node pred, Node curr, Node reuseNode) { this(pred, curr); this.reuseNode = reuseNode; } } /** * If element is present, returns node and predecessor. If absent, returns * node with least larger key. * @param head start of list * @param key key to search for * @return If element is present, returns node and predecessor. If absent, returns * node with least larger key. */ public Window find(Node head, int key) { Node pred = null, curr = null, succ = null, reuseNode = null; boolean[] marked = {false}; // is curr marked? boolean snip; retry: while (true) { pred = head; curr = pred.next.getReference(); while (true) { succ = curr.next.get(marked); while (marked[0]) { // replace curr if marked snip = pred.next.compareAndSet(curr, succ, false, false); if (!snip) continue retry; //fulltopic: get use node if(curr.key == key) { reuseNode = curr; } curr = pred.next.getReference(); succ = curr.next.get(marked); } if (curr.key >= key) return new Window(pred, curr, reuseNode); pred = curr; curr = succ; } } }}
118. 因为contains() --> find() 会忽略所有marked的节点。如果线性化的顺序是remove-->add-->contains,contains().find()会发现curr.key == key而不是停止在marked removed node with key == key。
- Art of Multiprocessor Programming 答案 ch9
- Art of Multiprocessor Programming 答案 ch3
- Art of Multiprocessor Programming 答案 ch2
- Art of Multiprocessor Programming 答案 ch4
- Art of Multiprocessor Programming 答案 ch5
- Art of Multiprocessor Programming 答案 ch6
- Art of Multiprocessor Programming 答案 ch7
- Art of Multiprocessor Programming 答案 ch8
- Art of Multiprocessor Programming 答案 ch10
- Art of Multiprocessor Programming 答案 ch11
- Art of Multiprocessor Programming 答案 ch12
- Art of Multiprocessor Programming 答案 ch13
- Art of Multiprocessor Programming 答案 ch14
- Art of Multiprocessor Programming 答案 ch15
- Art of Multiprocessor Programming 答案 ch16
- Art of Multiprocessor Programming 答案 ch17
- Art of Multiprocessor Programming 答案 ch8 p93
- Art of Multiprocessor Programming 答案 ch8 p96
- 基于TCP的网络应用程序
- 7.2
- xmpp学习笔记(一)
- 谈Hadoop下各技术应用场景
- IPtables 详解
- Art of Multiprocessor Programming 答案 ch9
- github问题之Unable to retrieve your user info from the server
- 好消息!C/C++各种开发环境搭建工具文档 免费视频教程重磅发布!
- Delphi 的自动构建工具WANT
- iOS开发学习笔记 2-3 C语言部分 控制流
- JavaScript初学者应知的24条最佳实践(译)
- 如何避免asp的SQL的执行效率低
- leetcode: Word Break
- HDU-1907 John