29.3.1 易变构造
当线程通过共享内存互相通信时,调用Volatile.Write来写入最后一个值,调用Volatile.Read来读取第一个值
public class ThreadsSharingData { private volatile int flag = 0; private int value = 0; public void Thread1() { //注意在将1写入flag之前,必须先将5写入value value = 5; flag = 1; } public void Thread2() { //注意在value必须在读取了flag之后才能读取 if (flag == 1) Console.WriteLine(value); } }
29.3.2 互锁构造
internal sealed class AsyncCoordinator { private int m_opCount = 1; private int m_statusReported = 0; private Action<CoordinatorStatus> m_callback; private Timer m_timer; public void AboutToBegin(int opsToAdd = 1) { Interlocked.Add(ref m_opCount, opsToAdd); } public void JuseEnded() { if (Interlocked.Decrement(ref m_opCount) == 0) ReportStatus(CoordinatorStatus.AllDone); } public void AllBegun(Action<CoordinatorStatus> callback, int timeout = Timeout.Infinite) { m_callback = callback; if (timeout != Timeout.Infinite) m_timer = new Timer(TimeExpired, null, timeout, Timeout.Infinite); JuseEnded(); } private void TimeExpired(object o) { ReportStatus(CoordinatorStatus.Timeout); ReportStatus(CoordinatorStatus.Cancel); } private void ReportStatus(CoordinatorStatus status) { if (Interlocked.Exchange(ref m_statusReported, 1) == 0) m_callback(status); } public enum CoordinatorStatus { AllDone, Timeout, Cancel } }
29.3.3 实现简单的自旋锁
class Program { private static SimpleSpinLock ssl = new SimpleSpinLock(); static void Main() { ssl.Enter(); //一次只有一个线程才能进入这里访问资源 ssl.Leave(); Console.ReadKey(); } } internal struct SimpleSpinLock { private int m_resourceInuse; //0=false,1=true public void Enter() { while (true) { //总是将资源设置为正在使用 //只有未使用变成正在使用才会返回 if (Interlocked.Exchange(ref m_resourceInuse, 1) == 0) return; //添加黑科技 } } public void Leave() { Volatile.Write(ref m_resourceInuse, 0); } }
29.3.4 Interlocked anything
delegate int Morpher<TResult, TArgument>(int startValue, TArgument argument, out TResult morphResult); private static TResult Morph<TResult, TArgument>(ref int target, TArgument argument, Morpher<TResult, TArgument> morpher) { TResult morphResult; int currentVal = target, startVal, desiredVal; do { startVal = currentVal; desiredVal = morpher(startVal, argument, out morphResult); currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); } while (startVal != currentVal); return morphResult; } private static int Maximun(ref int target, int value) { int currentVal = target, startVal, desiredVal; //不要在循环中访问目标target,除非想要改变它时另一个线程也在动它 do { //记录这一次循环的起始值startVal startVal = currentVal; //基于startVal和value计算desiredVal desiredVal = Math.Max(startVal, value); //注意:线程在这里可能被“抢占”,所以以下代码不是原子性的 //if (target == startVal) target = desiredVal; //使用原子性的方法,返回在target在(可能)被方法修改之前的值 currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal); } //如果target的值在这一次循环迭代中被其它线程改变,就重复 while (startVal != currentVal); return desiredVal; }