おそらく、私たちの多くは、次の同期プリミティブを見つけたり思いついたりしました。
ロックの取得 (コードは Pascal です):
while Cardinal(InterlockedExchange(fAccess, 1)) <> 0 do
Sleep(0);
そしてそれを解放します:
InterlockedExchange(fAccess, 0);
ネストされた呼び出しと互換性がないことがわかったとき、それを改善することに決め、新しい Aqcuire バリアントを次のコードとして実装しました (上記のフラグメントを 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 回ずつ増加させる 3 つのテスト スレッドでは、このコードがロックを取得できなかった回数は約 72 回でした。そのため、起動中のスレッドは、他のすべてのスレッドがほとんどの時間スリープしていることに気づきます。なんで?また、スレッドが異なるコアに存在する場合、衝突の数は大幅に増加しますか?