1

我们中的许多人可能发现或想出了以下同步原语:

获取锁(代码在 Pascal 中):

while Cardinal(InterlockedExchange(fAccess, 1)) <> 0 do 
  Sleep(0);

并释放它:

InterlockedExchange(fAccess, 0);

当我发现它与嵌套调用不兼容时,我决定对其进行改进并实现新的 Aqcuire 变体,如下代码(我们将上面的 Fragment 称为 Acquire/Release)

Acquired:=false;
repeat
  Acquire;
    if (fData.Thread = 0) or (fData.Thread = GetCurrentThreadId) then
    begin
      fData.Thread:=GetCurrentThreadId;
      Inc(fData.Level);
      Acquired:=true;
    end
    else
      Inc(fData.Failures);

    SleepAfter:=(not Acquired);
  Release;

  if SleepAfter then
    Sleep(0);
until Acquired;

和新版本

  Acquire;
    Dec(fData.Level);
    if fData.Level=0 then
      fData.Thread := 0
  Release;

这行得通,但令我困惑的是失败的数量很少(至少在单核系统上)。对于三个分别增加 10,000,000 次值的测试线程,这段代码无法获得锁的次数约为 72。我很高兴,但另一方面我无法理解背后的机制。因此,任何唤醒线程都会发现所有其他线程大部分时间都在休眠。为什么?如果线程位于不同的内核上,冲突的数量会显着增加吗?

4

0 回答 0