3

我正在Ref<T>使用无锁乐观更新方法进行小型抽象(应该使用不可变T数据结构,特别是不可变树)。它基于SpinWait 使用LockFreeUpdate部分中 Albahari 的“C#中的线程”方法:

static void LockFreeUpdate<T> (ref T field, Func <T, T> updateFunction) where T : class
{
  var spinWait = new SpinWait();
  while (true)
  {
    T snapshot1 = field;
    T calc = updateFunction (snapshot1);
    T snapshot2 = Interlocked.CompareExchange (ref field, calc, snapshot1);
    if (snapshot1 == snapshot2) return;
    spinWait.SpinOnce();
  }
}

我的问题是为什么我们在这里需要 SpinWait? 因为如果字段已经更新,那么另一个并发代码可以立即从新值重试更新。

下面提供了没有 SpinWait 的完整 Ref 代码(检查Update方法以进行比较):

public sealed class Ref<T> where T : class
{
    public T Value { get { return _value; } }

    public Ref(T initialValue = default(T))
    {
        _value = initialValue;
    }

    public T Update(Func<T, T> update)
    {
        var retryCount = 0;
        while (true)
        {
            var oldValue = _value;
            var newValue = update(oldValue);
            if (Interlocked.CompareExchange(ref _value, newValue, oldValue) == oldValue)
                return oldValue;
            if (++retryCount > RETRY_COUNT_UNTIL_THROW)
                throw new InvalidOperationException(ERROR_EXCEEDED_RETRY_COUNT);
        }
    }

    private T _value;

    private const int RETRY_COUNT_UNTIL_THROW = 10;
    private static readonly string ERROR_EXCEEDED_RETRY_COUNT =
        "Ref retried to Update for " + RETRY_COUNT_UNTIL_THROW + " times But there is always someone else intervened.";
}
4

0 回答 0