“通用构造”是顺序对象的包装器类,可使它线性化(并发对象的强一致性条件)。例如,这是来自Java [1]的一种经过修改的免等待构造,它假定存在一个满足接口的等待空闲队列WFQ
(仅需要线程之间的一次性共识)并假定一个Sequential
接口:
public interface WFQ<T> // "FIFO" iteration
{
int enqueue(T t); // returns the sequence number of t
Iterable<T> iterateUntil(int max); // iterates until sequence max
}
public interface Sequential
{
// Apply an invocation (method + arguments)
// and get a response (return value + state)
Response apply(Invocation i);
}
public interface Factory<T> { T generate(); } // generate new default object
public interface Universal extends Sequential {}
public class SlowUniversal implements Universal
{
Factory<? extends Sequential> generator;
WFQ<Invocation> wfq = new WFQ<Invocation>();
Universal(Factory<? extends Sequential> g) { generator = g; }
public Response apply(Invocation i)
{
int max = wfq.enqueue(i);
Sequential s = generator.generate();
for(Invocation invoc : wfq.iterateUntil(max))
s.apply(invoc);
return s.apply(i);
}
}
此实现的效果不是很令人满意,因为它确实很慢(您会记住每个调用,并且必须在每次应用时重播它-我们在历史记录大小中具有线性运行时)。有什么方法可以(以合理的方式)扩展WFQ
and Sequential
接口,以使我们能够在应用新调用时节省一些步骤?
我们可以提高效率(在历史记录大小上不是线性运行时,最好是内存使用量也会下降)而又不会丢失wait-free属性吗?
澄清度
我敢肯定,“通用构造”是由[1]组成的,该术语接受线程不安全但线程兼容的对象,该对象由Sequential
接口进行了概括。使用免等待队列,第一个构造提供了对象的线程安全,线性化版本,该对象也无需等待(这是确定性和暂停apply
操作的前提)。
这是低效率的,因为该方法有效地使每个本地线程从干净的位置开始并对其进行记录的每个操作。无论如何,这是WFQ
可行的,因为它通过使用确定所有操作应采用的顺序来有效地实现了同步:每个线程调用apply
都将看到相同的本地Sequential
对象,并对其应用相同的Invocation
s 序列。
我的问题是我们是否可以(例如)引入后台清理过程来更新“启动状态”,这样我们就不必从头开始。这并不像拥有带有起始指针的原子指针那样简单-这些方法很容易失去免等待保证。我怀疑其他一些基于队列的方法可能在这里起作用。
行话:
- 无需等待-不管线程数或调度程序的决策如何,
apply
都将以为该线程执行的可证明的有限数量的指令终止。 - 无锁-与上述相同,但仅
apply
在其他线程中完成无限制的操作的情况下,才允许执行时间不受限制。通常,乐观同步方案属于此类。 - 阻塞-效率取决于调度程序。
[1] Herlihy和Shavit,《多处理器编程的艺术》。
CopyableSequential
都有效-然后,线性化应该基于它的事实Sequential
。