我们中的许多人可能发现或想出了以下同步原语:
获取锁(代码在 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。我很高兴,但另一方面我无法理解背后的机制。因此,任何唤醒线程都会发现所有其他线程大部分时间都在休眠。为什么?如果线程位于不同的内核上,冲突的数量会显着增加吗?