如何实现我自己的锁定机制

时间:2011-09-28 20:53:55

标签: c# .net concurrency locking

对于一个赋值(如果你想知道它是并发的) - 我必须实现我自己的锁

(更具体:TaS,TTas和Array-Lock,如“多处理器编程的艺术”中所述)

我尝试过一些在线测试输入和输出方案(太糟糕了,他们需要很长时间才能尝试)。

  

您的计划是计算通过某项测试的9位数字

(它在荷兰语中被称为elfproef,我不知道英语对等,对不起)。

有时我的号码略有不同,这表示我的锁定无法正常 100%

我已经实现了这样的锁:

interface Lock
{
    void Lock();
    void Unlock();
}

class TaSLock : Lock
{
    AtomicBool state = new AtomicBool(false);

    void Lock.Lock()
    { while (state.getAndSet(true)); }

    void Lock.Unlock()
    { state.getAndSet(false); }
}

AtomicBool是使用integer实现的,因为Interlocked类没有Boolean个变量的操作。这在内存使用方面不是最佳的,但它不会(或不应该)对速度有影响。

class AtomicBool
{
    int value;
    static int True = 1, False = -1;

    public AtomicBool(bool value)
    {
        if (value) this.value = True;
        else this.value = False;
    }

    public void set(bool newValue)
    {
        if (newValue) Interlocked.Exchange(ref value, True);
        else Interlocked.Exchange(ref value, False);
    }

    public bool getAndSet(bool newValue)
    {
        int oldValue;
        if (newValue) oldValue = Interlocked.Exchange(ref value, True);
        else oldValue = Interlocked.Exchange(ref value, False);
        return (oldValue == True);
    }

    public bool get()
    {
        return (Interlocked.Add(ref value, 0) == 1);
    }
}

现在我刚刚使用的并行部分:

theLock.Lock();
counter++;
theLock.Unlock();

但每次我得到的结果都略有不同。

有什么明显我做错了吗?

1 个答案:

答案 0 :(得分:9)

汉斯是对的。你的原子获取和设置布尔似乎是正确的 - 实际上,在我看来它有点过度设计。而且锁定似乎也是正确的,因为你已经为自己构建了一个潜在的非常低效的“自旋锁”。 (也就是说,所有等待的线程都只是紧紧地坐在那里问“我可以去吗?我可以去吗?”而不是睡觉直到轮到他们。)

不正确的是,您的锁无法保证任何两个都具有“计数器”视图的线程都具有“计数器”的一致视图。两个线程可以在不同的处理器上,并且那些不同的处理器可以在其高速缓存中具有不同的“计数器”副本。缓存的副本将被更新,并且只会偶尔写回主内存,从而有效地“丢失”一些增加。

锁定C#的真正实现可确保强制执行全栅栏内存屏障,以便读取和写入不会跨越栅栏“向前和向后移动”。这给了处理器一个提示,他们不需要那么聪明地如此积极地缓存“反击”。