在一篇文章中有关A scalable reader/writer scheme with optimistic retry有一个代码示例:C#可以写入指令从finally块重新排序到try块吗?
using System;
using System.Threading;
public class OptimisticSynchronizer
{
private volatile int m_version1;
private volatile int m_version2;
public void BeforeWrite() {
++m_version1;
}
public void AfterWrite() {
++m_version2;
}
public ReadMark GetReadMark() {
return new ReadMark(this, m_version2);
}
public struct ReadMark
{
private OptimisticSynchronizer m_sync;
private int m_version;
internal ReadMark(OptimisticSynchronizer sync, int version) {
m_sync = sync;
m_version = version;
}
public bool IsValid {
get { return m_sync.m_version1 == m_version; }
}
}
public void DoWrite(Action writer) {
BeforeWrite();
try {
writer(); // this is inlined, method call just for example
} finally {
AfterWrite();
}
}
public T DoRead<T>(Func<T> reader) {
T value = default(T);
SpinWait sw = new SpinWait();
while (true) {
ReadMark mark = GetReadMark();
value = reader();
if (mark.IsValid) {
break;
}
sw.SpinOnce();
}
return value;
}
}
如果我让m_version1
和m_version2
不挥发但随后使用代码:
public void DoWrite(Action writer) {
Thread.MemoryBarrier(); // always there, acquiring write lock with Interlocked method
Volatile.Write(ref m_version1, m_version1 + 1); // NB we are inside a writer lock, atomic increment is not needed
try {
writer();
} finally {
// is a barrier needed here to avoid the increment reordered with writer instructions?
// Volatile.Write(ref m_version2, m_version2 + 1); // is this needed instead of the next line?
m_version2 = m_version2 + 1; // NB we are inside a writer lock, atomic increment is not needed
Thread.MemoryBarrier(); // always there, releasing write lock with Interlocked method
}
}
可能从行指令m_version2 = m_version2 + 1
进行重新排序从finally
转换为try
块?在m_version2
递增前,作者完成这一点很重要。
逻辑finally
在try
之后执行,但finally
块在list of implicit memory barriers中未提及。 如果来自finally
的指令可能会在try
之前被移动,但是在指令级别对CPU的优化对我来说仍然是一个黑魔法,这将是相当混淆的。
我可以把Thread.MemoryBarrier();
放在行m_version2 = m_version2 + 1
(或使用Volatile.Write
)之前,但问题是这是否真的需要?
示例中显示的MemoryBarrier
是隐式的,并且由作者锁定的方法生成,所以它们始终存在。危险是读者在作家完成之前可以看到m_version2
递增。
发布此消息后,我已阅读http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf。它看起来像Volatile.Write是需要的,没有特别的处理'finally'(I.12.6-7节)。除非我错过了关于CERs的一些细节。 –