在一篇文章中有關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的一些細節。 –