Art of Multiprocessor Programming 答案 ch12

134.

135,136题我认为应该是这样,但是测试失败了,还在查。

135.

package p135;

public class Node 
{
	  enum CStatus{IDLE, FIRST, SECOND, THIRD, RESULT, ROOT};
	  boolean locked = false;
	  CStatus status;
	  int firstValue;
	  int secondValue;
	  int thirdValue;
	  int result;
	  Node parent;
	  int drained = 0;
	  
	  public Node()
	  {
		  status = CStatus.ROOT;
		  parent = null;
		  locked =false;
	  }
	  
	  public Node(Node parent)
	  {
		  this.parent = parent;
		  status = CStatus.IDLE;
		  locked = false;
	  }
	  
	  synchronized CStatus precombine() throws InterruptedException, UnexpectedStatusException
	  {
		  while(drained == 2 || locked) wait();
		  
		  switch(status)
		  {
		  //Return IDLE or FIRST is of no significance
		  case IDLE:
			  status = CStatus.FIRST;
			  return CStatus.IDLE; 
		  case FIRST:
			  drained = 1;
			  status = CStatus.SECOND;
			  return CStatus.SECOND;
		  case SECOND:
			  drained = 2;
			  status = CStatus.THIRD;
			  return CStatus.THIRD;
		  case ROOT:
			  return CStatus.ROOT;
		  default:
			throw new UnexpectedStatusException();	  
		  }
	  }
	  
	  synchronized int combine(int combined) throws InterruptedException, UnexpectedStatusException
	  {
		  while(drained > 0) wait();
		  locked = true;
		  firstValue = combined;
		  
		  switch(status)
		  {
		  case FIRST:
			  return firstValue;
		  case SECOND:
			  return firstValue + secondValue;
		  case THIRD:
			  return firstValue + secondValue + thirdValue;
		  default:
			  throw new UnexpectedStatusException();
		  }
	  }
	  
	  synchronized int op(int combined, CStatus myStatus) throws InterruptedException, UnexpectedStatusException
	  {
		  switch(myStatus)
		  {
		  case ROOT:
			  int oldValue = result;
			  result += combined;
			  return oldValue;
		  case SECOND:
			  secondValue = combined;
			  drained = 0;
			  notifyAll();
			  while(status != CStatus.RESULT) wait();
			  locked = false;
			  notifyAll();
			  status = CStatus.IDLE;
			  return secondValue;
		  case THIRD:
			  switch(myStatus)
			  {
			  case SECOND: 
				  secondValue = combined;
				  break;
			  case THIRD:
				  thirdValue = combined;
				  break;
			  default:
				break;					  
			  }
			  if(--drained == 0)
			  {
				  notifyAll();
			  }
			  while(status != CStatus.RESULT) wait();
			  locked = false;
			  notifyAll();
			  status = CStatus.IDLE;
			  return thirdValue;
		  default:
			  throw new UnexpectedStatusException();
		  }
	  }
	  
	  synchronized void distribute(int prior) throws UnexpectedStatusException
	  {
		  switch(status)
		  {
		  case FIRST:
			  status = CStatus.IDLE;
			  locked = false;
			  break;
		  case SECOND:
			  secondValue = prior + firstValue;
			  status = CStatus.RESULT;
			  break;
		  case THIRD:
			  thirdValue = prior + firstValue + secondValue;
			  status = CStatus.RESULT;
			  break;
		  default:
			throw new UnexpectedStatusException();	  
		  }
		  notifyAll();
	  }
}
package p135;

import java.util.Stack;

import p135.Node.CStatus;

public class Tree 
{
	Node[] leaf;
	public ThreadLocal
   
   
    
     ThreadId = new ThreadLocal
    
    
     
     ()
	{
		protected Integer initialValue()
		{
			return new Integer(0);
		}
	};
	
	public Tree(int y)
	{
		int size = ((int)Math.pow(3, (y + 1)) - 1) / (3 - 1);
		Node[] nodes = new Node[size];
		nodes[0] = new Node();
		for(int i = 1; i < size; i ++)
		{
			nodes[i] = new Node(nodes[(i - 1) / 3]);
		}
		
		int leafSize = (int)Math.pow(3, y);
		leaf = new Node[leafSize];
		for(int i = 0; i < leaf.length; i ++)
		{
			leaf[i] = nodes[nodes.length - i - 1];
		}
	} 
	
	public int getAndIncrement() 
	{
//		System.out.println("Try to increment by " + ThreadId.get());
		CStatus myStatus = CStatus.IDLE;
		Stack
     
     
      
       stack = new Stack
      
      
       
       ();
		Node myLeaf = leaf[ThreadId.get()];
		Node node = myLeaf;
		int prior = 0;
		try
		{
		while((myStatus = node.precombine()) == CStatus.IDLE)
		{
			node = node.parent;
		}
		Node stop = node;
		
		node = myLeaf;
		int combined = 1;
		while(node != stop)
		{
			combined = node.combine(combined);
			stack.push(node);
			node = node.parent;
		}
		
		prior = node.op(combined, myStatus);
		
		while(!stack.empty())
		{
			node = stack.pop();
			node.distribute(prior);
		}
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		
		return prior;
	}
}
package p135;

public class UnexpectedStatusException extends Exception
{
	private static final long serialVersionUID = -531756879106132777L;

	public UnexpectedStatusException()
	{
		super();
	}
}

      
      
     
     
    
    
   
   

136.

package p136;


import java.util.concurrent.Exchanger;
import p135.UnexpectedStatusException;

/*
 * Node.java
 *
 * Created on October 29, 2005, 8:59 AM
 *
 * From "The Art of Multiprocessor Programming",
 * by Maurice Herlihy and Nir Shavit.
 * Copyright 2006 Elsevier Inc. All rights reserved.
 */

/**
 * Node declaration for software combining tree.
 * @author Maurice Herlihy
 */
public class Node {
  enum CStatus{IDLE, FIRST, SECOND, RESULT, ROOT};
  boolean locked;   // is node locked?
  CStatus cStatus;  // combining status
  int firstValue, secondValue; // values to be combined
  int result;       // result of combining
  Node parent;      // reference to parent
  Exchanger
   
   
    
     sendUp;
  Exchanger
    
    
     
      sendDown;
  int index;
  
  /** Creates a root Node */
  public Node() {
    cStatus = CStatus.ROOT;
    locked = false;
    index = 0;
  }
  /** Create a non-root Node */
  public Node(Node _parent, int index) {
    parent = _parent;
    cStatus = CStatus.IDLE;
    locked = false;
    sendUp = new Exchanger
     
     
      
      ();
    sendDown = new Exchanger
      
      
       
       ();
    this.index = index;
  }
  
  synchronized boolean precombine() throws InterruptedException, UnexpectedStatusException
  {
    while (locked) wait();
    switch (cStatus) {
      case IDLE:
        cStatus = CStatus.FIRST;
        return true;
      case FIRST:
//        locked = true;
        cStatus = CStatus.SECOND;
        System.out.println("SECOND in precombine");
        return false;
      case ROOT:
        return false;
      default:
        throw new UnexpectedStatusException();
    }
  }
  
  synchronized int combine(int combined) throws InterruptedException, UnexpectedStatusException
  {
//    while (locked) wait();
    locked = true;
    firstValue = combined;
    switch (cStatus) {
      case FIRST:
        return firstValue;
      case SECOND:
          System.out.println("SECOND in combine");    	  
        int rc = firstValue + sendUp.exchange(null);
        System.out.println("SECOND after combine");    	  
        return rc;
      default:
        throw new UnexpectedStatusException();
    }
  }
  
  synchronized int op(int combined) throws InterruptedException, UnexpectedStatusException
  {
    switch (cStatus) {
      case ROOT:
        int oldValue = result;
        result += combined;
        return oldValue;
      case SECOND:
//        secondValue = combined;
          System.out.println("SECOND before exchange up");

    	sendUp.exchange(combined);
//        locked = false;
//        notifyAll();
//        while (cStatus != CStatus.RESULT) wait();
        System.out.println("SECOND before exchange down");
        result = sendDown.exchange(null);
        locked = false;
        cStatus = CStatus.IDLE;
        notifyAll();
        return result;
      default:
        throw new UnexpectedStatusException();
    }
  }
  synchronized void distribute(int prior) throws InterruptedException, UnexpectedStatusException
  {
    switch (cStatus) {
      case FIRST:
        cStatus = CStatus.IDLE;
        locked = false;
        break;
      case SECOND:
//        result = prior + firstValue;
    	sendDown.exchange(prior + firstValue);
        cStatus = CStatus.RESULT;
        break;
      default:
        throw new UnexpectedStatusException();
    }
//    notifyAll();
  }
  
  public int get()
  {
	  return index;
  }
  
}

      
      
     
     
    
    
   
   


137.

同queue


138.

139.

package p139;

import java.util.concurrent.atomic.AtomicInteger;

public class Balancer 
{
	AtomicInteger counter;
	
	public Balancer()
	{
		counter = new AtomicInteger(0);
	}
	
	public int traverse()
	{
		int count = counter.getAndIncrement();
		
		if(count % 2 == 0)
		{
			return 0;
		}else
		{
			return 1;
		}
	}
}

140.

采用归纳法证明:假设 T[k]有布进特性,用T[k]构成T[2k]网后,进入 T[0][k]和进入T[1][k]的令牌最多相差1个。则根据引理12.5.1.2,另T[0].j = c,则T[1].j = c || T[1].j = c - 1

case 1: T[0].j = c && T[1].j = c && (c % 2) == 0

令T[0][i] = a (i <= j),则T[1][i] = a (i <= j)。经过输出线重定向得到:T[1] = T[0][1] = a, T[2] = T[1][1] = a, ... T[(c - 1) * 2] = T[0][c - 1] = a, T[c * 2] = T[1][c - 1] = a, ... , T[i] = (a - 1)..., T[2k] = (a - 1)。

case 2: T[0].j = c && T[1].j = (c - 1) && (c % 2) == 0

case 3: T[0].j = c && T[1].j = c && (c % 2) == 1

case 4: T[0].j = c && T[1].j = (c - 1) && (c % 2) == 1

case 5: j 不存在

都做类似证明。


141.

用归纳法证明:

假设 m = 2 ^ (d - 1)个令牌从一个输出线上穿过深度为d - 1的网络后B在令牌离开网络后的状态与进入前的状态相同,则第m+1个令牌通过d-1层网络后到达的第d层的输入线与第1个令牌到达输入线相同。如果第d层的这个balancer的状态为1(被翻转),则第m+1个令牌将它的状态恢复,如果状态为0(已经被恢复),则m+2 ~ n个令牌中的某些会像1 ~m个令牌的行为一样将其恢复。


142.

令X的输出为x,Y的输出为y;min(x) = ux, min(y) = uy;

经过匹配后的Z的输出为z,则 max(z) = ceil(((max(x) + max(y)) / 2), min(z) = floor(((min(x) + min(y)) / 2) 

==> max(z) - min(z) = ceil(((max(x) + max(y)) / 2) - floor((ux + uy) / 2) 

        <= ceil( (ux + k + uy + k) / 2 ) - floor((ux + uy) / 2) 

        = ceil( (ux + uy) / 2 + k) - floor( (ux + uy) / 2) <= k + 1


143.

Block[k]的深度为logk,每一个深度对应一个Balancer,每一个balancer都是1-光滑的,经过logk层后,有142知是logk-光滑的


144.

因为S是光滑网,所以令从S的输出线上输出的令牌数为k或者k+1,输出线上的前k个令牌经过P后输出仍然是每线输出为k,平衡。剩下的令牌分散在P的输入线上,有的输入线输入为1(个令牌),有的输入线输入为0;因为P是布尔排序网的同构网,所以可以对1/0输入进行排序,即值为1的输入将在值为0的输入之前输出;将输入为1与有令牌输入对应,输入为0与无令牌输入对应;即P将对剩下的令牌排序。


145.


如图所示。


146.

令n为距离w最近而且>w的2的幂,构建宽度为n的BitomicSort,将w与n的gap用最小值补齐


147.

1.以设置filter[v]为可线性化点,题目中说了,每个线程等待其它具有较小值的线程赶上,设置自己的filter相,然后返回。即可以根据v值得到全序,并且v值较小的在前。等待比自己小的线程到达实际上是等待自己前一个线程将filter[v-1]值翻转。如果翻转,表示确实等到同一轮v-1的到来。如果已经翻转,但不是同一轮的v-1,则翻转这个值的必然是v-1+2*w或者v-1-2*w。如果由v-1-2*w翻转的,则表示v-1-w线程还没有到达,则v-w线程不能返回,即v线程并不能开始,矛盾;所以不可能是v-1-2*w线程翻转的,类似的也不是v-1+2*w线程翻转的。

2.

3. 有更高的吞吐量。首先filter网采用spin last anticipator的方案,类似于CLH队列锁,在SMP上比所有线程spin在同一个变量上效率高;而且在进入filter之前先经过吞吐量由于单个锁的排序网,缩短了在前一个变量上spin的时间,减小了需要等待的几率。


148.

首先证明k-光滑的X穿过深度为1的平衡网后仍然是k-光滑的。

假设x[i]穿过了平衡器,则必然与某一个x[j]平衡,得到的输出y[i]=ceil( (x[i] + x[j]) / 2), y[j] = floor( (x[i] + x[j]) / 2)

==> max(X) >= y[i] >= y[j] >= min(X) 

否则如果x[i]没有经过平衡器,则仍然有

==> max(X) >= y[i] >= min(X)

所以有任何  |y[k] - y[i]| <= k,即仍然是k-光滑序列。

然后可以用归纳法证明,如果X经过了深度为d的平衡网仍然是k-光滑的,则经过d+1的平衡网后也是k-光滑的。


149.

1. 因为M(2w) = M(w) + 1 ==> M(w) = log(w) + 1;

    又B(2w) = B(w) + M(2w) 

                    = log(w) * (log(w) + 1) / 2 + log(w) + 1

                    = ( log(w) * log(w) + 3log(w) + 2) / 2

                    = (1 + log(w)) * ( 2 + log(w)) / 2

                    = log(2*w) * ( log(2 * w) + 1) / 2

                    = B(2w)

2.

M(2w) = 2 * M(w) + 2 ==> M(w) = w * log(w) / 2

B(2w) = 2 * B(w) + M(2w)

            = (2*w*log(w) 2 * w * (log(w) ^ 2)) / 4 + wlog(w) + w

            = (2 * w * log(2w)) * (1 + log(2w)) / 2

归纳法得证。


150.

如果Balancer是无锁的,DiffractingBalancer就是无锁的?


151.

类似并发栈的消除策略:prism成功的次数增加则增加slot的范围,失败的次数增加则减小slot的范围,当slot减小到一定程度可以取消prism,直接走balancer。


152.

一个反例:

3个token从1线输入它们的路径分别是

1->1->1

1->2->2

1->1->1


153.

假设深度为d的网络N满足这个性质,令在后面加一层的网络为N'。则第 (2 ^ d) + 1个令牌通过N后与第1个令牌的输出线相同,当它通过第d+1层的平衡器时,无论令牌是否反令牌,(2 ^ d) + 1个令牌都将恢复第1个令牌改变的第d + 1层平衡器。所以经过 ( 2 ^ d) * 2个令牌,即( 2 ^ (d + 1))个令牌后 N'也将恢复成初始状态。


154.

因为反令牌的行为是翻转toggle并返回未翻转的值,所以这个反令牌必然跟踪原来的令牌所走的相同路线并将令牌翻转过的平衡器恢复。


155.

一个反令牌根据平衡器的当前值移动,并恢复平衡器的状态,而且权重为-1。因此可以将一个反令牌的行为看成一个令牌的行为的反:一个反令牌之所以经过某一条路径而不是另一条是因为有一个令牌已经经过了这条路径(这个令牌的动作可能发生在反令牌通过网络之后)。即一个反令牌在网络达到静态后可以抵消某个令牌。所以如果有a个令牌和b各反令牌通过了网络,其行为相当于a - b个令牌经过了这个网络,由于网络是计数网,网络将对a - b个令牌平衡,即对输出线上的令牌和反令牌权重和平衡,符合有反令牌的平衡网的定义。


156.

Adding Networks

这篇论文是本书作者关于adding network的论文,比题目的描述要详细。

大意是如果按照题目描述的token的顺序和行为,t将在adding-network的出线返回a,t1返回a + b,t2返回a + 2*b ...

本书题目中说的ti可以在S的某个交换器上终结,意思是ti必然经过S中的某个交换器。

论文的第7页给了正式的证明,没有完全看懂,求指教。

大概的意思是用归纳法:

令s为S中的任一交换器。

起始:

因为t1要返回a + b,t1的路径必须经过s:因为adding-network并不能产生数值和token,如果t1不经过s,a不能凭空产生。

归纳:反证

如果ti在t之后穿过adding-network,ti在出线上应该得到a + i * b。

但是因为ti经过的路径没有经过s,整个交换网在 t经过然后(t1, t2, ..., ti)经过 与 只有(t1, t2, ..., ti)然后t经过 没有区别。但是前者ti的出线值是a + i * b;后者的出线值是 i * b。无法区分。

所以ti必然经过s

得证。


157.

计数网是加法网的一种,即每次加a = b = 1的加法网,所以深度也至少为n。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值