なぜCASビジー待ちのループに同等とみなされていませんか?

キリアン:

ここ数日でロックフリーのプログラミングについて少し読んで、私はaccrossに来たutil.java.Random次のルーチンを使用して、それのビットを作成するクラス:

protected int next(int bits) {
    long oldseed, nextseed;
    AtomicLong seed = this.seed;
    do {
        oldseed = seed.get();
        nextseed = (oldseed * multiplier + addend) & mask;
    } while (!seed.compareAndSet(oldseed, nextseed));
    return (int)(nextseed >>> (48 - bits));
}

よると、この SOの答え:

いわゆるロックフリーアルゴリズムはタイトビジー待ちのCAS命令とを使用する傾向があるが、競合は、CPUが通常は数回の反復処理する必要があること、低いので、通常の状況です。

そして、ウィキペディア

代わりにCAS操作が失敗した直後にリトライ、研究者は、システム全体のパフォーマンスは、マルチプロセッサシステム、彼らのCAS失敗を参照してくださいスレッドは指数バックオフ・言い換えれば、待ち時間を使用する多くのスレッドが常にいくつかの特定の共有場合は、変数を更新して改善することができることを見出しましたCASを再試行する前に少し。[4]

Wikipediaの記事を理解することができる、それが判明したが、それはまだ使用していないか、CAS命令が人為的にバックオフ、彼らが失敗した後のが一般的です。これは、このようなループがCPU使用率に関するまたはCASは常に争われていないため、危険とはみなされない理由は?

2番目の質問:特定の理由がための基準があるseed作成されたか、我々はまた、単にクラススコープからの変数を使用することができますか?

ピーター・コルド:

CASのものにしようとして複数のスレッドがロックフリー(しかし、待って、無料ではない)です。スレッドの一つは、彼らがすべて同じで試みるたびに進行行いますold値をhttps://en.wikipedia.org/wiki/Non-blocking_algorithm

(かどうかの複数のスレッドは、すべて同じ読みold値をまたは一部が別のスレッドのCASの結果を参照するかどうかのタイミングに依存しており、そこにどのくらいの競合を決定するものは基本的です。)

これは、単にいくつかの未知の長さの操作を待っていると、ロックを保持しているスレッドがスケジュール解除された場合、無期限に立ち往生することができ、通常のビジー待機ループとは異なります。その場合、あなたは間違いなくあなたのCASはロックを取得するために失敗した場合、あなたは間違いなくあなたが成功する前に何かをする別のスレッドを待つ必要があるため、バックオフにしたいです。


通常、ロックなしのアルゴリズムは、洗練された指数バックオフが本当に必要されていない低競合状況で使用されています。これは、リンクされたSOの答えが言っていることです。

これは、キー:Wikiの記事で述べたような状況の違い、多くのスレッドが常にいくつかの特定の共有変数を更新しますそれは一つのスレッドが行の更新の束を行い、そのL1Dキャッシュにホットラインを維持させるために、おそらくより良いですのでそれは、高競合状況です。(あなたがアトミック倍精度FPの追加、のように、ハードウェアで直接サポートされていないことをアトミック操作を実装するためにCASを使用していると仮定するshared.CAS(old, old+1.0)か何か。または、ロックレスキューか何かの一部として。)

あなたは非常に実際に競合してCASループを使用していた場合、それはいくつかのバックオフし、スループットの合計助け、例えばのx86実行可能性があるpauseキャッシュラインに打っ少ないコアを持って、再び試みる前に、失敗した場合に命令を。あなたは間違いなくバックオフする必要がありますのでまたはロックレスキューに対して、あなたはそれがいっぱいだったか、空に見つけた場合、それは基本的に待ちのため、別のスレッド状況です。


x86の以外のほとんどのアーキテクチャが持つ原始その原子RMWとしてLL / SCをハードウェアに直接CAS、ありません。他のスレッドでもされている場合LLのうちの建物CAS / SCは、見かけ上失敗することができます読ん CAS試行中にキャッシュラインを、可能性があるので、ない少なくとも一つのスレッドが成功することを保証します。

うまくいけば、ハードウェア設計者は、メイクLL / SCは、競合からのスプリアスの障害に耐えることのCPUをしようが、私は詳細を知りません。この場合、バックオフは、潜在的なライブロックを避けるために役立つかもしれません。

(CASが誤って競合から失敗することはできませんハードウェアでは、ライブロックのようなもののために不可能ですwhile(!shared.CAS(old, old<<1)){}。)


インテルの最適化マニュアルがロックが、無料になるのを待っているの例を有する場合、それらのループ1 << retry_countこれがあることに注意してください(一部の最大バックオフファクタまで)倍ではない通常のCASループそのロックレスアルゴリズムの者の一部。これはです実装するロックを。

ロックがフリーになるのバックオフが待っているだけでなく、ロック自体を含むキャッシュラインへのアクセスの競合のために、。

  /// Intel's optimization manual
  /// Example 2-2. Contended Locks with Increasing Back-off Example

  /// from section 2.2.4 Pause Latency in Skylake Microarchitecture
  /// (~140 cycles, up from ~10 in Broadwell, thus max backoff should be shorter)
/*******************/
/*Baseline Version */
/*******************/
// atomic {if (lock == free) then change lock state to busy}
while (cmpxchg(lock, free, busy) == fail)
{
   while (lock == busy)
     _mm_pause();
}


/*******************/
/*Improved Version */
/*******************/
int mask = 1;
int const max = 64; //MAX_BACKOFF
while (cmpxchg(lock, free, busy) == fail)
{
   while (lock == busy)
   {
      for (int i=mask; i; --i){
         _mm_pause();
      }
      mask = mask < max ? mask<<1 : max;    // mask <<= 1  up to a max
   }
}

ロックを待っているとき、私はあなたの代わりにCMPXCHGにしようとして維持するのスピン読み取り専用にしたい、正常に思いました。私は、Intelからこの例では、と思うだけでロック解除スレッドを遅らせないようにするロックを最適化する方法の他の部分は、バックオフを実証していません。

とにかく、その例がある覚えていない私たちはロックレスキューまたはCAS-再試行アトミック追加の実装や他のプリミティブと話をしているもののように。それは、ロックを解除するために別のスレッドを待っていない古い値を読み取り、新しい値にCASにしようとの間で登場した新しい値を使用してからちょうど失敗。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=187971&siteId=1