1

おそらく、私たちの多くは、次の同期プリミティブを見つけたり思いついたりしました。

ロックの取得 (コードは 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 回でした。そのため、起動中のスレッドは、他のすべてのスレッドがほとんどの時間スリープしていることに気づきます。なんで?また、スレッドが異なるコアに存在する場合、衝突の数は大幅に増加しますか?

4

0 に答える 0