对于一个赋值(如果你想知道它是并发的) - 我必须实现我自己的锁
(更具体: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();
但每次我得到的结果都略有不同。
有什么明显我做错了吗?
答案 0 :(得分:9)
不正确的是,您的锁无法保证任何两个都具有“计数器”视图的线程都具有“计数器”的一致视图。两个线程可以在不同的处理器上,并且那些不同的处理器可以在其高速缓存中具有不同的“计数器”副本。缓存的副本将被更新,并且只会偶尔写回主内存,从而有效地“丢失”一些增加。
锁定C#的真正实现可确保强制执行全栅栏内存屏障,以便读取和写入不会跨越栅栏“向前和向后移动”。这给了处理器一个提示,他们不需要那么聪明地如此积极地缓存“反击”。