Art of Multiprocessor Programming 答案 ch15

本文探讨了SimpleTree在多处理器编程中的静态一致性性质,分析了如何处理超过预设阈值的情况,以及如何在无锁编程中利用AtomicBoolean确保线性化。还提到了线程间的冲突点,例如在removeMin和add操作中的潜在问题,以及全局锁中创建对象的开销。重点讨论了静态一致性的概念及其在实现中的应用。
摘要由CSDN通过智能技术生成

173. SimpleTree 是不可线性化但是静态一致的。


174. 思路是

如果不要求保存状态可重用,则可以在输出端连接H个开关,比如说,如果output=1已经有token经过了,则当前counter>H,返回H。

如果考虑可重用,则发现>H则再加入一个反令牌,<0则再加入一个令牌。一个问题是如何在decrement用反令牌实现的前提下用开关标记是否是超过H的。

因为衍射树是静态一致的,AtomicBoolean也是静态一致的,他们的组合也是静态一致的。

package p174;

public class Balancer {
	  Boolean toggle;
	  
	  public Balancer() 
	  {
	    toggle = true;
	  }
	  
	  public synchronized int traverse(boolean token) 
	  {
		  if(token)
		  {
			  try 
			  {
				  if (toggle) 
				  {
					  return 0;
				  } else 
				  {
					  return 1;
				  }
			  } finally 
			  {
				  toggle = !toggle;
			  }
		  }else
		  {
			  toggle = !toggle;
			  if(toggle)
			  {
				  return 0;
			  }else
			  {
				  return 1;
			  }
		  }
	  }
}
	  



package p174;

public class DiffractingTree
{
	Balancer root;
	DiffractingTree[] child;
	int size;
	
	public DiffractingTree(int mySize)
	{
		size = mySize;
		root = new Balancer();
		if(size > 2)
		{
			child = new DiffractingTree[]
				{
					new DiffractingTree(size / 2),
					new DiffractingTree(size / 2),
				};
		}
	}
	
	public int traverse(boolean token)
	{
		int half = root.traverse(token);
		
		if(size > 2)
		{
			return (2 * (child[half].traverse(token)) + half);
		}else
		{
			return half;
		}
	}
}


package p174;

import java.util.concurrent.atomic.AtomicBoolean;

public class Counter 
{
	private final int bound;
	private DiffractingTree tree;
	private AtomicBoolean flags[];
	
	public Counter(int bound)
	{
		this.bound = bound;
		tree = new DiffractingTree(bound);
		flags = new AtomicBoolean[bound];
		
		for(int i = 0; i < flags.length; i ++)
		{
			flags[i] = new AtomicBoolean(false);
		}
	}
	
	public int boundedGetAndIncrement()
	{
		int tmpRc = tree.traverse(true);
		if(flags[tmpRc].compareAndSet(false, true))
		{
			return tmpRc;
		}else
		{
			tmpRc = tree.traverse(false);
			flags[tmpRc].compareAndSet(true, false);
			return bound;
		}
	}
	
	public int boundedGetAndDecrement()
	{
		int tmpRc = tree.traverse(false);
		
		if(flags[tmpRc].compareAndSet(true, false))
		{
			return tmpRc;
		}else
		{
			tmpRc = tree.traverse(true);
			flags[tmpRc].compareAndSet(false, true);
			return 0;
		}
	}
	
	public static void main(String[] args)
	{
		Counter counter = new Counter(4);
		
		for(int i = 0; i < 2; i ++)
		{
			int rc = counter.boundedGetAndIncrement();
			System.out.println("" + i + "---------> " + rc);
		}
		
		for(int i = 0; i < 9; i ++)
		{
			int rc = counter.boundedGetAndDecrement();
			System.out.println("-" + i + "---------> " + rc);
		}
	}
}


175.

负数,非零,走到错误的叶子。


176. 看不懂题目。这个本来就是有界容量的。


177.

removeMin超过add,在内部节点中发现无路可走。


178.


179.

import java.util.ArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Heap with fine-grained locking and arbitrary priorities.
 * @param T type manged by heap
 * @author mph
 */
public class FineGrainedHeap
   
   
    
     implements PQueue
    
    
     
      {

  private static int ROOT = 1;
  private static int NO_ONE = -1;
  private Lock heapLock;
  int next;
//  HeapNode
     
     
      
      [] heap;
  ArrayList
      
      
       
       
         > heap; /** * Constructor * @param capacity maximum number of items heap can hold */ public FineGrainedHeap(int capacity) { heapLock = new ReentrantLock(); next = ROOT; heap = new ArrayList 
         
         
           >(capacity + 1); } /** * Add item to heap. * @param item Uninterpreted item. * @param priority item priority */ public void add(T item, int priority) { heapLock.lock(); int child = next++; if(heap.size() <= child) { HeapNode 
          
            childElem = new HeapNode 
           
             (); heap.add(childElem); } //It should be right as next ++, add new element are sequential as they were locked by helpLock. //And there is no removal operation from list. //Anyway, the get(child) can throw Exception when index and element really mismatched. heap.get(child).lock(); heapLock.unlock(); //... } //... } 
            
           
          
         
       
      
      
     
     
    
    
   
   

临时创建对象的开销,尤其是在全局锁中创建对象的开销。


180.

好处在于如果没有这个特性,相邻的2个插入在时间上是相差最短的,而且最容易有相同的父节点,所以产生同步开销的机率最大。


以 reverseIncrement为例:



public int reversedIncrement()
{
    //如果counter越界,则归零
    if(count ++ == 0)
    {
        reverse = highBit = 1;
        return reverse;
    }
    
    //取bit为除了最高位的第一位。即根结点下的第一层子树位。
    int bit = highBit >> 1;
    
    while(bit != 0)
    {
        //从高位开始异或,所以相邻的2个节点必然不在同一个子树上。
        reverse ^= bit;
        
        /*
        * 因为reverse ^= bit,又(reverse & bit == 0) 
        * ==> 假设bit = 0100,则异或之前reverse = x0xx
        * ==> 原来的reverse在左树上,则找到右子树上的对应节点,退出。
        * ==> 如果原来的reverse在右树上,则异或后转到左子树
        * ==> 且bit >>= 1,即到下一层子树继续这个过程,直到找到一个右子树上的点。
        * 
        * ==> 以上图为例,count = 8对应的reverse为1000,为子树1的最左节点
        * ==> count = 9时,因为8在左子树,找到子树1的右子树的对应节点为12
        * ==> count = 10,第一轮找到对称节点为8,在左子树,
        *   ==> 下降一层,到子树2的右子树上找对应的节点,找到10
        * ==> count = 11,找到1的右子树的对应节点14
        * ==> count = 12,第一轮得到对应节点为10,在左子树,
        *   ==> 下降一层,在子树2上,得到对应节点为8,得知原节点在2的右子树上,
        *       ==> 下降一层,在子树4上,得到对应右节点为9
        * ==> ...
        * ==> count = 15,得到节点15
        * ==> count = 16,
        */
        if((reverse & bit) != 0)
        {
            break;
        }
        bit >>= 1;
    }
    
    /*
    * count = 16,得到bit = 0,即叶子节点层已经没有空余节点了
    * 将最高位左移一位,即树高加一层,并在新层上找next。
    */
    if(bit == 0)
    {
        reverse = highBit << = 1;
    }
    
    return reverse;
}

181.

作者有给出


182.

不从头开始也是可以的,因为要求只是静态一致性。

package p182;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;



public class LazySkipListQueue
   
   
    
    
{
	static final int MAX_LEVEL = 4;
	static int randomSeed = (int)(System.currentTimeMillis()) | 0x0100;
	
	private static int randomLevel() {
		int x = randomSeed;
		x ^= x << 13;
		x ^= x >>> 17;
		randomSeed = x ^= x << 5;
		if ((x & 0x80000001) != 0) // test highest and lowest bits
			return 0;
		int level = 1;
		while (((x >>>= 1) & 1) != 0) ++level;
		return Math.min(level, MAX_LEVEL-1);
	}
	private static final class Node
    
    
     
     
	{
		final Lock lock  = new ReentrantLock();
		final T item;
		final int priority;
		final Node
     
     
      
      [] next;
		volatile boolean marked = false;
		volatile boolean fullLinked = false;
		private int topLevel;
		@SuppressWarnings("unchecked")
		public Node(int priority)
		{
			this.item = null;
			this.priority = priority;
			next = (Node
      
      
       
       [])new Node[MAX_LEVEL + 1];
			topLevel = MAX_LEVEL;
		}
		
		@SuppressWarnings("unchecked")
		public Node(T x, int priority)
		{
			this.item = x;
			this.priority = priority;
			int height = randomLevel();
			next =  (Node
       
       
         [])new Node[height + 1]; topLevel = height; } public void lock() { lock.lock(); } public void unlock() { lock.unlock(); } } final Node 
        
          head = new Node 
         
           (Integer.MIN_VALUE); final Node 
          
            tail = new Node 
           
             (Integer.MAX_VALUE); public LazySkipListQueue() { for(int i = 0; i < head.next.length; i ++) { head.next[i] = tail; } } int find(Node 
            
              node, Node 
             
               [] preds, Node 
              
                [] succs) { int lFound = -1; Node 
               
                 pred = head; for(int level = MAX_LEVEL; level >= 0; level --) { Node 
                
                  curr = pred.next[level]; while(node.priority > curr.priority) { pred = curr; curr = pred.next[level]; } if(lFound == -1 && node.priority == curr.priority) { lFound = level; } preds[level] = pred; succs[level] = curr; } return lFound; } @SuppressWarnings("unchecked") boolean add(Node 
                 
                   newNode) { int topLevel = randomLevel(); Node 
                  
                    [] preds = (Node 
                   
                     []) new Node[MAX_LEVEL + 1]; Node 
                    
                      [] succs = (Node 
                     
                       []) new Node[MAX_LEVEL + 1]; while(true) { int lFound = find(newNode, preds, succs); if(lFound != -1) { Node 
                      
                        nodeFound = succs[lFound]; if(!nodeFound.marked) { while(!nodeFound.fullLinked){} return false; } continue; } int highestLocked = -1; try { Node 
                       
                         pred, succ; boolean valid = true; for(int level = 0; valid && (level < topLevel); level ++) { pred = preds[level]; succ = succs[level]; pred.lock(); highestLocked = level; valid = !pred.marked && !succ.marked && pred.next[level] == succ; } if(!valid) { continue; } for(int level = 0; level <= topLevel; level ++) { newNode.next[level] = succs[level]; } for(int level = 0; level <= topLevel; level ++) { preds[level].next[level] = newNode; } newNode.fullLinked = true; return true; }finally { for(int level = 0; level <= highestLocked; level ++) { preds[level].unlock(); } } } } @SuppressWarnings("unchecked") private boolean remove(Node 
                        
                          victim) { boolean isMarked = false; Node 
                         
                           [] preds = (Node 
                          
                            []) new Node[MAX_LEVEL + 1]; Node 
                           
                             [] succs = (Node 
                            
                              []) new Node[MAX_LEVEL + 1]; int topLevel = victim.topLevel; while(true) { int lFound = find(victim, preds, succs); if(!(lFound != -1 && lFound == victim.topLevel && victim.marked)) { return true; } victim.lock(); int highestLocked = -1; try { Node 
                             
                               pred; boolean valid = true; for(int level = 0; valid && (level <= topLevel); level ++) { pred = preds[level]; pred.lock(); highestLocked = level; valid = !pred.marked && pred.next[level] == victim; } if(!valid) { continue; } for(int level = topLevel; level >= 0; level --) { preds[level].next[level] = victim.next[level]; } victim.unlock(); return true; }finally { for(int i = 0; i <= highestLocked; i ++) { preds[i].unlock(); } } } } public Node 
                              
                                findAndMarkMin() { Node 
                               
                                 ret = null; Node 
                                
                                  pred = null; Node 
                                 
                                   curr = null; while(true) { pred = head; curr = pred.next[0]; while(curr.marked && curr != tail) { pred = curr; curr = pred.next[0]; } if(curr == tail) { return null; }else { try { pred.lock(); curr.lock(); if(!curr.marked && !pred.marked && pred.next[0] == curr) { curr.marked = true; ret = curr; remove(ret); return ret; } }finally { pred.unlock(); curr.unlock(); } } } } } 
                                  
                                 
                                
                               
                              
                             
                            
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   

183.

2个线程同时findAndRemoveMin,因为都是从head开始沿list[bottom]寻找,所以很有可能在head.next[0]上冲突。


184.

因为有了全局同步的时间,所以任何相关事件都可以全排序,所以可以线性化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值