198. 如果线程 k + 2^r 比 线程 k 快很多,当线程 k + 2^r 读 a[k]的时候将读到没有 sum k段的原始值,没有求和的作用。
public void run() {
int d = 1, sum = 0;
while (d < N) {
if (i >= d)
sum = a[i-d];
b.await();
if (i >= d)
a[i] += sum;
b.await();
d = d * 2;
}}}
代码来自书作者ppt。
199.
package p199;
import java.util.concurrent.atomic.AtomicInteger;
public class SenseBarrier
{
private AtomicInteger count;
private final int size;
private boolean sense;
private ThreadLocal
threadSense;
public SenseBarrier(int n)
{
count = new AtomicInteger(n);
size = n;
sense = false;
threadSense = new ThreadLocal
()
{
protected Boolean initialValue() { return !sense; };
};
}
public void await()
{
boolean mySense = threadSense.get();
int position = count.getAndDecrement();
if(position == 1)
{
count.set(size);
sense = mySense;
this.notifyAll();
}else
{
while(sense != mySense)
{
try
{
this.wait();
}catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
threadSense.set(!mySense);
}
}
当参与的线程行为不确定性强,响应时间要求不高,cpu不希望独占是采用wait的方式合适;否则采用spin比较合适。
200.
package ch17.basic;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class TreeNode
{
protected AtomicInteger count;
protected TreeNode parent;
protected volatile boolean sense;
protected final int radix;
public TreeNode(int radix)
{
sense = false;
parent = null;
this.radix = radix;
count = new AtomicInteger(radix);
}
public TreeNode(int radix, TreeNode parent)
{
this(radix);
this.parent = parent;
}
public void nodeNotify()
{
return;
}
abstract public void await();
abstract public void build(int depth, Integer leaves, TreeNode leaf[]);
}
package ch17.p200;
import ch17.basic.Barrier;
import ch17.basic.TreeNode;
public class RunnableTree implements Barrier
{
final int radix;
Node[] leaf;
int leaves;
ThreadLocal
threadSense;
ThreadLocal
ThreadID;
Runnable task;
final int n;
public RunnableTree(int n, int radix, Runnable task)
{
this.radix = radix;
this.n = n;
leaves = 0;
threadSense = new ThreadLocal
()
{
protected Boolean initialValue() { return true; };
};
ThreadID = new ThreadLocal
()
{
protected Integer initialValue() { return 0; };
};
this.task = task;
build();
}
public void await()
{
int me = ThreadID.get();
Node myNode = leaf[me / radix];
myNode.await();
}
private void build()
{
leaf = new Node[n / radix];
int depth = 0;
int layNum = n;
while(layNum > 1)
{
depth ++;
layNum = layNum / radix;
}
Node root = new Node(radix);
Integer leaveNum = new Integer(0);
root.build(depth, leaveNum, leaf);
leaves = leaveNum;
}
private class Node extends TreeNode
{
public Node(int radix)
{
super(radix);
}
public Node(int radix, Node myParent)
{
super(radix, myParent);
}
public void build(int depth, Integer leaves, TreeNode leaf[])
{
if(depth < 0)
{
return;
}
if(depth == 0)
{
leaf[leaves] = this;
leaves ++;
return;
}
for(int i = 0; i < radix; i ++)
{
Node node = new Node(radix, this);
node.build(depth - 1, leaves, leaf);
}
}
public void await()
{
boolean mySense = threadSense.get();
int position = count.getAndDecrement();
if(position == 1)
{
if(parent != null)
{
parent.await();
}else
{
task.run();
}
count.set(radix);
sense = mySense;
}else
{
while(sense != mySense) {}
}
threadSense.set(!mySense);
}
}
}
201.
package ch17.p201;
import ch17.basic.TreeNode;
public class GeneralTree
{
protected final int radix;
protected TreeNode[] leaf;
protected int leaves;
protected ThreadLocal
ThreadID;
protected final int n;
protected TreeNode root;
//The inherited class should have root initiated
public GeneralTree(int n, int radix, TreeNode root)
{
this.radix = radix;
this.n = n;
leaves = 0;
ThreadID = new ThreadLocal
()
{
protected Integer initialValue() { return 0; };
};
this.root = root;
build();
}
public void await()
{
int me = ThreadID.get();
TreeNode myNode = leaf[me / radix];
myNode.await();
}
protected void build()
{
leaf = new TreeNode[n / radix];
int depth = 0;
int layNum = n;
while(layNum > 1)
{
depth ++;
layNum = layNum / radix;
}
Integer leaveNum = new Integer(0);
root.build(depth, leaveNum, leaf);
leaves = leaveNum;
}
}
202.
package ch17.p202;
public class TourBarrier
{
TourNode[] nodes;
TourNode[] leaf;
ThreadLocal
ThreadID;
ThreadLocal
threadSense;
public TourBarrier(int n)
{
ThreadID = new ThreadLocal
()
{
protected Integer initialValue() { return 0; };
};
this.threadSense = new ThreadLocal
() {
protected Boolean initialValue() { return true; };
};
int nodeNum = (1 << n) - 1;
nodes = new TourNode[nodeNum];
int rootIndex = 0;
nodes[rootIndex] = new TourNode(rootIndex);
nodes[rootIndex].build(n - 1, nodes);
int leafNum = (1 << (n - 1));
leaf = new TourNode[leafNum];
for(int i =0; i < leafNum; i ++)
{
leaf[leafNum - i - 1] = nodes[nodeNum - i - 1];
}
}
public void await()
{
int me = ThreadID.get();
TourNode myLeaf = leaf[me / 2];
boolean sense = threadSense.get();
myLeaf.await(sense);
threadSense.set(!sense);
}
private class TourNode
{
final int myIndex;
volatile boolean flag;
boolean active;
int parentIndex;
int partnerIndex;
public TourNode(int index)
{
this.myIndex = index;
this.flag = false;
this.active = false;
this.parentIndex = -1;
setPartnerIndex();
}
public TourNode(int parentIndex, int index)
{
this(index);
this.active = true;
this.parentIndex = parentIndex;
}
private void setPartnerIndex()
{
if(myIndex % 2 == 0)
{
this.partnerIndex = myIndex + 1;
}else
{
this.partnerIndex = myIndex - 1;
}
}
public int getIndex()
{
return myIndex;
}
public void build(int depth, TourNode nodes[])
{
if(depth < 0)
{
System.out.println("Invalid depth");
return;
}else if(depth == 0)
{
return;
}else
{
int leftIndex = this.myIndex * 2 + 1;
int rightIndex = (this.myIndex * 2) + 2;
nodes[leftIndex] = new TourNode(this.getIndex(), leftIndex);
nodes[rightIndex] = new TourNode(rightIndex);
nodes[leftIndex].build(depth - 1, nodes);
nodes[rightIndex].build(depth - 1, nodes);
}
}
public void await(boolean sense)
{
if(active)
{
if(parentIndex >= 0)
{
while(flag != sense) {}
nodes[parentIndex].await(sense);
nodes[partnerIndex].flag = sense;
}
}else
{
nodes[partnerIndex].flag = sense;
while(flag != sense){}
}
}
}
}
203.
这是不对的.因为每次在特定节点上竞争的线程是不固定的.比如,4个线程的树, 第一次由线程1和线程3到达root,假设所有ThreadLocal初始值为false,则线程1和3从root返回后mySense = true;同时线程2和线程4在root上的mySense=false;root的sense = false。第二次barrier由线程2和4到达,线程2发现sense == mySense,于是没有与线程同步而直接从root返回。
204.
这种树的算法是不正确的。
如果障碍的用法是先执行操作,然后等待在树上,则有可能出现的情形是,左子树的所有节点都已经完成操作,右子树的所有Active节点都到达parent直至root,但是有的passive节点还没有完成phaseI的操作 ==》左子树节点都从root向下返回,并开始phaseII的操作。这是可能会涉及与右子树节点的交互,并在不同步的状态下得到结果作为phaseII的结果。
如果障碍的用法是先在树上等待返回再执行操作:障碍的正确性在于如果不是所有的线程都完成了phase1则不能开始phase2。但是这个算法只能保证如果不是所有线程都开始phase1则不能开始phase2。比如这样的情形:左右子树的所有节点都已经开始执行phase1==》所有的active节点都完成了phase1的操作==》所有active节点向root回溯 ==》根结点的左子树都已经完成phase1 ==》根结点的左子树的所有节点都开始执行phase2但是右子树还有节点正在执行phase1 ==》不同步的状态。
205.
package ch17.p205;
import counting.Bitonic;
public class CounterBarrier implements ch17.basic.Barrier
{
private Bitonic counter;
private volatile boolean sense;
private ThreadLocal
ThreadId;
private ThreadLocal
threadSense;
private final int size;
public CounterBarrier(int size)
{
this.size = size;
this.sense = false;
this.counter = new Bitonic(size);
ThreadId = new ThreadLocal
()
{
protected Integer initialValue() { return 0; };
};
this.threadSense = new ThreadLocal
() {
protected Boolean initialValue() { return (!sense); };
};
}
public void await()
{
int myId = ThreadId.get();
boolean mySense = threadSense.get();
int output = counter.traverse(myId);
if((output % this.size) == 0)
{
sense = !sense;
}else
{
while(mySense != this.sense) {}
}
threadSense.set(!mySense);
}
}
206.
package ch17.p206;
import register.WFSnapshot;
public class SnapshotBarrier implements TDBarrier
{
private WFSnapshot
snapshot;
// ThreadLocal
ThreadId;
public SnapshotBarrier(int capacity)
{
snapshot = new WFSnapshot
(capacity, false);
}
public void setActive(boolean state)
{
snapshot.update(state);
}
public boolean isTerminated()
{
Boolean[] results = snapshot.scan();
for(int i = 0; i < results.length; i ++)
{
if(results[i])
{
return false;
}
}
return true;
}
}
207.
可以用归纳法证明,当一个线程完成了第i步,即已经收到了i-(2^r)(mod n)的通知 ,则线程k已经与线程 k - 1, k - 2, ..., k - (2 ^ i ) + 1 同步了。
假设在i 时为真,则 i + 1时,线程k在i是已经与前 (2 ^ i)个线程同步了,同时线程k与线程( k - (2 ^ i))同步,线程( k - (2 ^ i)) 已经与线程 (k -(2 ^ i)), (k - (2 ^ i) - 1), ... , (k - (2 ^ (i + 1)) + 1) 同步了。得证。
所以要所有的线程都与其他的线程同步,需要 logn轮同步。
如果线程数不是2 ^ i,也没有关系,只是线程k在同步时,同步的前第1到第n个线程,与第n+1到2n个线程会有重叠的部分。但是并不会有重复的消息,只要能够消息能够区分是针对哪一步。因为先发后收,也不会有死锁。
208.
package ch17.p208;
public class DisBarrier implements ch17.basic.Barrier
{
private final int size;
private final int powSize;
volatile private boolean[][] flags;
private ThreadLocal
ThreadId;
private ThreadLocal
flag;
public DisBarrier(int powSize)
{
this.powSize = powSize;
this.size = (int)Math.pow(2, powSize);
flags = new boolean[size][];
for(int i = 0; i < size; i ++)
{
//initialized as all false
flags[i] = new boolean[powSize];
}
ThreadId = new ThreadLocal
()
{
protected Integer initialValue() { return 0; };
};
flag = new ThreadLocal
()
{
protected Boolean initialValue() { return true; };
};
}
public void await()
{
int myId = ThreadId.get();
boolean myFlag = flag.get();
int step = 1;
for(int i = 0; i < powSize; i ++)
{
int toIndex = (myId + step) % size;
flags[toIndex][i] = myFlag;
while(flags[myId][i] != myFlag) {}
step <<= 1;
}
flag.set(!myFlag);
}
}
209.
设线程数为 n = (r ^ d), 树为r叉树,一共有(1 - (r ^d)) / (1 - r)个节点。
组合树:每个节点经过了r个getAndDecrement操作,2个反转操作(setCounter, !sense)和r个 threadSense反转操作。
静态树:每个节点经历了r个递减操作和r个threadSense反转操作。
分发树:每个线程经历了 logn轮的操作,每轮包括一个发消息操作和一个收消息操作。
更具体的分析见 barrier
210.
package ch17.p210;
import java.util.concurrent.atomic.AtomicInteger;
import programm.ch17.Barrier.src.barrier.TDBarrier;
public class ActiveTDBarrier implements TDBarrier
{
AtomicInteger count;
ThreadLocal
ThreadId;
final int capacity;
AtomicInteger totalActivated;
Runnable[] tasks;
DEQueue[] queues;
public ActiveTDBarrier(int n, DEQueue[] queue, Runnable[] tasks)
{
this.count = new AtomicInteger(0);
this.capacity = n;
this.queues = queue;
this.tasks = tasks;
totalActivated = new AtomicInteger(0);
ThreadId = new ThreadLocal
()
{
protected Integer initialValue() { return 0; };
}; // TODO Auto-generated constructor stub
}
public void setActive(boolean active)
{
if(active)
{
count.getAndIncrement();
totalActivated.getAndIncrement();
}else
{
count.getAndDecrement();
}
}
public boolean isTerminated()
{
int localActivated = totalActivated.get();
int checkNum = 0;
while(checkNum < 2)
{
if(count.get() != 0)
{
return false;
}
if(localActivated != totalActivated.get())
{
return false;
}
//No one moves in between count reading
//task may be pushed in queue or popped out the queue
for(int i = 0; i < queues.length; i ++)
{
if(!queues[i].isEmpty())
{
return false;
}
}
//task my be pushed in queue or popped out the queue or running
for(int i = 0; i < tasks.length; i ++)
{
if(tasks[i] != null)
{
return false;
}
}
//task may be popped out the queue or new task pushed into queue
/*After first check, the new task may be
in queue
or in task
or had finished
They could be detected by
queue check
or task check
or totalActivated
*/
checkNum ++;
}
return localActivated == totalActivated.get();
}
}
package ch17.p210;
import java.util.Random;
public class ActiveTDThread
{
DEQueue[] queue;
ActiveTDBarrier tdBarrier;
Runnable[] tasks;
Random random;
final static int QueueSize = 64;
public ActiveTDThread(int n) {
queue = new DEQueue[n];
tasks = new Runnable[n];
tdBarrier = new ActiveTDBarrier(n, queue, tasks);
random = new Random();
for (int i = 0; i < n; i++) {
queue[i] = new DEQueue(QueueSize);
}
for(int i = 0; i < n; i ++)
{
tasks[i] = null;
}
}
public void run()
{
int me = ThreadID.get();
tdBarrier.setActive(true);
tasks[me] = queue[me].popBottom(); // attempt to pop 1st item
while (true)
{
while (tasks[me] != null)
{ // if there is an item
tasks[me].run(); // execute it and then
tasks[me] = queue[me].popBottom(); // pop the next item
}
tdBarrier.setActive(false); // no work
while (tasks[me] == null)
{ // steal an item
int victim = random.nextInt(queue.length);
if (!queue[victim].isEmpty())
{
tdBarrier.setActive(true); // tentatively active
tasks[me] = queue[victim].popTop();
if (tasks[me] != null)
{
tdBarrier.setActive(true);
}
}
if (tdBarrier.isTerminated())
{
return;
}
}
}
}
}