Art of Multiprocessor Programming 答案 ch11

本文探讨了在多核环境下,如何通过引入回退延迟策略减少共享栈的冲突,以及解决ABA问题和线程同步问题。讨论了如何在push和pop操作中避免数据丢失,以及如何在并发操作中确保数据一致性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

126.

package p126;

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

public class UnboundListStack
{
	public class Node
	{
		private T item;
		public Node next;
		
		public Node(T item)
		{
			this.item = item;
			this.next = null;
		}
		
		public T get()
		{
			return item;
		}
	}
	
	private Lock lock;
	private Node head;
	
	public UnboundListStack()
	{
		this.lock = new ReentrantLock();
		head = new Node(null);
	}
	
	public void push(T x)
	{
		Node node = new Node(x);
		
		lock.lock();
		
		try
		{
			node.next = head.next;
			head.next = node;
		}finally
		{
			lock.unlock();
		}
	}
	
	public T pop() throws Exception
	{
		lock.lock();
		
		try
		{
			if(head.next == null)
			{
				throw new Exception("Empty");
			}else
			{
				T item = head.next.get();
				head.next = head.next.next;
				return item;
			}
		}finally
		{
			lock.unlock();
		}
	}
	
}
127.

package p126;

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

public class UnboundListStack
{
	public class Node
	{
		private T item;
		public Node next;
		
		public Node(T item)
		{
			this.item = item;
			this.next = null;
		}
		
		public T get()
		{
			return item;
		}
	}
	
	private Lock lock;
	private Node head;
	
	public UnboundListStack()
	{
		this.lock = new ReentrantLock();
		head = new Node(null);
	}
	
	public void push(T x)
	{
		Node node = new Node(x);
		
		lock.lock();
		
		try
		{
			node.next = head.next;
			head.next = node;
		}finally
		{
			lock.unlock();
		}
	}
	
	public T pop() throws Exception
	{
		lock.lock();
		
		try
		{
			if(head.next == null)
			{
				throw new Exception("Empty");
			}else
			{
				T item = head.next.get();
				head.next = head.next.next;
				return item;
			}
		}finally
		{
			lock.unlock();
		}
	}
	
}

128.

package p128;

import java.util.concurrent.atomic.AtomicStampedReference;

import utils.EmptyException;
import ch7.Backoff;

public class LockFreeStack
{
	public class Node
	{
		public T value;
		public Node next;
		public Node(T value)
		{
			this.value = value;
			next = null;
		}
	}
	
	static final int INITCAPACITY = 2;
	ThreadLocal nodeList = new ThreadLocal()
	{
		protected Node initialValue()
		{
			Node head = new Node(null);
			
			for(int i = 0; i < INITCAPACITY; i ++)
			{
				Node node = new Node(null);
				node.next = head.next;
				head.next = node;
			}
			
			return head;
		}
	};
	
	private Node allocNode()
	{
		Node head = nodeList.get();
		if(head.next == null)
		{
			return new Node(null);
		}else
		{
			Node node = head.next;
			head.next = head.next.next;
			node.next = null;
			return node;
		}
	}
	
	private void freeNode(Node node)
	{
		if(node == null)
		{
			return;
		}
		node.value = null;
		Node head = nodeList.get();
		node.next = head.next;
		head.next = node;
	}
	
	AtomicStampedReference top = new AtomicStampedReference(null, 0);
	static final int MIN_DELAY = 1;
	static final int MAX_DELAY = 10;
	Backoff backoff = new Backoff(MIN_DELAY, MAX_DELAY);
	
	protected boolean tryPush(Node node)
	{
		int[] stamp = new int[1];
		Node oldTop = top.get(stamp);
		node.next = oldTop;
		return (top.compareAndSet(oldTop, node, stamp[0], stamp[0] + 1));
	}
	
	public void push(T value)
	{
		Node node = allocNode();
		node.value = value;
		while(true)
		{
			if(tryPush(node))
			{
				return;
			}else
			{
				try
				{
					backoff.backoff();
				}catch(Exception e)
				{
					e.printStackTrace();
				}
			}
		}
	}
	
	protected Node tryPop() throws EmptyException
	{
		int[] stamp = new int[1];
		Node oldTop = top.get(stamp);
		if(oldTop == null)
		{
			throw new EmptyException();
		}
		Node newTop = oldTop.next;
		if(top.compareAndSet(oldTop, newTop, stamp[0], stamp[0] + 1))
		{
			return oldTop;
		}else
		{
			return null;
		}
	}
	
	public T pop() throws EmptyException
	{
		while(true)
		{
			Node returnNode = tryPop();
			if(returnNode != null)
			{
				T value = returnNode.value;
				freeNode(returnNode);
				return value;
			}else
			{
				try
				{
					backoff.backoff();
				}catch(Exception e)
				{
					e.printStackTrace();
				}			
			}
		}
	}
}

129.

1. 意义在于push和pop都是在top上的冲突,所以他们共享同一个backoff才能比较好的减少冲突。

2. 根据:add additional backoff delays before accessing the shared stack, and control whether to access the shared stack or the array dynamically。在policy中增加关于tryPush()和tryPop()成功和失败的计数。假设成功次数为s,失败次数为f,则成功率为 s / (s + f);则在tryPush()之前生成随机数r,如果 r % ((s + f) / s) == 0,则直接尝试tryPush(),否则直接从exchangers 入栈。

130.

将EliminationBackoffStack去掉tryPush和tryPop的部分,并将exchangers' capacity设为题目要求的界限。

131.

有类似于ABA的问题,比如:

1. top = 2, --> T1.pop() --> top = 1 --> T1.pop.i = 2, stack[2].value = value.T0

==> T2.pop() --> top = 0

==> T3.push() --> top = 1

==> T4.push() --> top = 2--> stack[2].value = value.T4; stack[2].full = true

==> T1.stack[2].full == true --> T1.pop() = value.T4

即T0写入的值被覆盖,丢失了。

2. top = 2 --> T1.pop --> top = 1 --> T1.i = 2

==> T2.push --> top = 2 --> T2.pushed

==> T3.pop --> top = 1, T3.i = 2

==> T3 && T1 pop the same item

问题在于push线程和pop线程之间没有同步,push线程并不知道当前操作的slot是否已经被pop了,即不能做到1对1。多个线程可能得到同一个index,因为取得index和读写操作并不原子,所以写/读的时候没有互斥;另外如果pop和push的速度太失衡,比如top.increase的速度总是赶不上pop.decrease的速度,会活锁。

package p131;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

import utils.EmptyException;
import utils.FullException;

public class DualStack
{
	public class Slot
	{
		public static final int EMPTY = 0;
		public static final int FULL = 1;
		public static final int BUSY = 2;

		volatile T value = null;
		AtomicStampedReference state = new AtomicStampedReference(EMPTY, 0);
	}
	
	Slot[] stack;
	int capacity;
	
	private AtomicInteger top = new AtomicInteger(0);
	
	@SuppressWarnings("unchecked")
	public DualStack(int myCapacity)
	{
		this.capacity = myCapacity;
		
		stack = new DualStack.Slot[capacity];
//		stack = (Slot[]) new Object[capacity];

		for(int i = 0; i < capacity; i ++)
		{
			stack[i] = new Slot();
		}
	}
	
	public void push(T value) throws FullException
	{
		while(true)
		{
			int i = top.getAndIncrement();
			if(i > capacity - 1)
			{
				top.compareAndSet(i, capacity);
				throw new FullException("" + i);
			}else if(i >= 0)
			{
				while(stack[i].state.getReference().intValue() != Slot.EMPTY) {}
				int[] stamp = new int[1];
				@SuppressWarnings("unused")
				int state = stack[i].state.get(stamp);
				if(!stack[i].state.compareAndSet(Slot.EMPTY, Slot.BUSY, stamp[0], stamp[0] + 1))
				{
					continue;
				}
				stack[i].value = value;
				stack[i].state.set(Slot.FULL, stamp[0] + 1);
//				System.out.println("stack " + i + " set full");
				return;
			}
		}
	}
	
	public T pop() throws EmptyException
	{
		while(true)
		{
			int i = top.getAndDecrement() - 1;
			if(i < 0)
			{
				top.compareAndSet(i + 1, 0);
				throw new EmptyException("" + (i + 1));
			}else if(i < capacity)
			{
//				System.out.println("Try to pop " + i);
				while(stack[i].state.getReference().intValue() != Slot.FULL) {}
				int[] stamp = new int[1];
				@SuppressWarnings("unused")
				int state = stack[i].state.get(stamp);
				T value = stack[i].value;
				if(!stack[i].state.compareAndSet(Slot.FULL, Slot.EMPTY, stamp[0], stamp[0]))
				{
					continue;
				}
				return value;
			}
		}
	}
	
	public int get()
	{
		return top.get();
	}
}

132.

1. 有131题类似的问题;还有越界的问题。比如:

T1.pop, top = -1 --> T2.pop, top = -2 --> T3.push, top = -1, items[-1] = x;

2. 如下所示。Rooms保证在所有的线程在由push和pop工作的转换中是静态一致的,所以保证操作的i都是有效的。同时如果2个push线程得到同一个index,他们之间必然已经隔了一段pop的执行;而在这个pop之前,第一个push线程必然已经完成items[i]=x的操作。如果这个slot没有被pop,则在第二次push阶段因为i = top.getAndIncrement()也不会被覆盖。

package p132;

import java.util.concurrent.atomic.AtomicInteger;

import p97.Rooms;
import utils.EmptyException;
import utils.FullException;

public class RoomsStack
{
	private AtomicInteger top;
	private T[] items;
	private Rooms rooms;
	public static final int PUSH = 0;
	public static final int POP = 1;
	
	@SuppressWarnings("unchecked")
	public RoomsStack(int capacity)
	{
		top = new AtomicInteger(0);
		items = (T[]) new Object[capacity];
		rooms = new Rooms(2);
	}
	
	public void push(T x) throws FullException
	{
		rooms.enter(PUSH);
		try
		{
			int i = top.getAndIncrement();
			if(i >= items.length)
			{
				top.getAndDecrement();
				throw new FullException();
			}
			items[i] = x;
		}finally
		{
			rooms.exit();
		}
	}
	
	public T pop() throws EmptyException
	{
		rooms.enter(POP);
		try
		{
			int i = top.getAndDecrement();
			if(i < 0)
			{
				top.getAndIncrement();
				throw new EmptyException();
			}
			return items[i];
		}finally
		{
			rooms.exit();
		}
	}
}

133.

	private class ExitHandler implements Rooms.Handler
	{
		public void onEmpty()
		{
			int newSize = items.length;
			@SuppressWarnings("unchecked")
			T[] newItems = (T[]) new Object[newSize];
			for(int i = 0 ; i < items.length; i ++)
			{
				newItems[i] = items[i];
			}
			items = newItems;
		}
	}
	
		@SuppressWarnings("unchecked")
	public RoomsStack(int capacity)
	{
		top = new AtomicInteger(0);
		items = (T[]) new Object[capacity];
		rooms = new Rooms(2);
		rooms.setExitHandler(PUSH, new ExitHandler());
	}
	
	public void push(T x)
	{
		while(true)
		{
			rooms.enter(PUSH);
			int i = top.getAndIncrement();
			if(i >= items.length)
			{
				top.getAndDecrement();
				rooms.exit();
			}else
			{
				items[i] = x;
				return;
			}
		}
	}


以下是彩色图像的PSNRSSIMLPIPS和CIEDE2000评价算法的Matlab源码示例: 1. PSNR(峰值信噪比): ```matlab function psnr_value = PSNR(original, distorted) [M, N, ~] = size(original); mse = sum((original(:) - distorted(:)).^2) / (M * N * 3); max_value = max(original(:)); psnr_value = 10 * log10(max_value^2 / mse); end ``` 2. SSIM(结构相似性指数): ```matlab function ssim_value = SSIM(original, distorted) K1 = 0.01; K2 = 0.03; L = 255; C1 = (K1 * L)^2; C2 = (K2 * L)^2; original = double(original); distorted = double(distorted); mean_original = filter2(fspecial('gaussian', 11, 1.5), original, 'valid'); mean_distorted = filter2(fspecial('gaussian', 11, 1.5), distorted, 'valid'); var_original = filter2(fspecial('gaussian', 11, 1.5), original.^2, 'valid') - mean_original.^2; var_distorted = filter2(fspecial('gaussian', 11, 1.5), distorted.^2, 'valid') - mean_distorted.^2; cov_original_distorted = filter2(fspecial('gaussian', 11, 1.5), original .* distorted, 'valid') - mean_original .* mean_distorted; ssim_map = ((2 * mean_original .* mean_distorted + C1) .* (2 * cov_original_distorted + C2)) ./ ((mean_original.^2 + mean_distorted.^2 + C1) .* (var_original + var_distorted + C2)); ssim_value = mean2(ssim_map); end ``` 3. LPIPS(感知相似性指标):需要下载并使用LPIPS库,源码和使用说明可在https://github.com/richzhang/PerceptualSimilarity 找到。 4. CIEDE2000(CIE 2000色差公式):需要下载并使用CIEDE2000库,源码和使用说明可在https://www.mathworks.com/matlabcentral/fileexchange/46861-color-difference-cie-de2000 找到。 以上是基本的示例代码,用于评估图像质量的不同评价指标。你可以根据实际需求和图像数据进行适当的调整和修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值