1. ホーム
  2. c++

[解決済み] スピンロックとセマフォの比較

2022-07-22 23:31:26

質問

セマフォとスピンロックの基本的な違いは何ですか?

どのような場合に、スピンロックではなくセマフォを使用するのでしょうか?

どのように解決するのですか?

スピンロックとセマフォの違いは主に4点です。

1. 両者が何であるか

A スピンロック は、ロックの実装の1つで、ビジー状態での待機 ("spinning") によって実装されています。セマフォはロックの一般化です (あるいは逆に、ロックはセマフォの特別なケースです)。通常は とは限りません。 スピンロックは1つのプロセス内でのみ有効ですが、セマフォは異なるプロセス間でも同期するために使用することができます。

ロックは相互排他的に働きます。 1 スレッドがロックを取得し、コードの重要なセクションを処理することができます。通常、これは複数のスレッドで共有されるいくつかのデータを変更するコードを意味します。

A セマフォ はカウンタを持ち、それ自身を 一つまたは複数の スレッドによって取得されることを許可します。

このことから、ロックは最大値が1のセマフォの特殊なケースであると考えることができます。

2. 何をするのか

上記のように、スピンロックはロックであり、したがって相互排除(厳密には1対1)メカニズムです。通常アトミックな方法で、メモリロケーションを繰り返し問い合わせたり変更したりすることで機能します。つまり、スピンロックの取得は、長い間(おそらく永遠に!)CPUサイクルを消費し、効果的に何も達成しない操作です。

このようなアプローチの主な動機は、コンテキストスイッチが数百回(または千回)回転するのと同等のオーバーヘッドを持つという事実です。したがって、回転する数サイクルを消費してロックを取得できる場合、これは全体的に非常に効率的である可能性があります。また、リアルタイム アプリケーションでは、ブロックしてスケジューラーが未来の遠い時間に戻ってくるのを待つことは許容されないかもしれません。

対照的に、セマフォはまったく回転しないか、非常に短い時間だけ回転します (syscall オーバーヘッドを回避するための最適化として)。セマフォが取得できない場合、ブロックされ、実行可能な別のスレッドに CPU 時間を譲ります。これはもちろん、スレッドが再びスケジュールされる前に数ミリ秒が経過することを意味するかもしれませんが、これが問題でなければ(通常はそうではありません)、非常に効率的でCPUを節約するアプローチになります。

3. 輻輳の存在下でどのように振舞うか

スピンロックやロックフリーのアルゴリズムは一般的に高速である、あるいは非常に短いタスクにしか有効でないというのはよくある誤解です(理想的には、同期オブジェクトは絶対に必要以上に長く保持されるべきではありません、決して)。

1 つの重要な違いは、異なるアプローチがどのように動作するかです。 輻輳の存在下で .

よく設計されたシステムでは、通常、輻輳は少ないか全くありません(これは、すべてのスレッドが全く同時にロックを取得しようとしないことを意味します)。例えば、通常 ではなく ロックを取得し、ネットワークから半分のメガバイトの zip 圧縮データをロードし、データをデコードして解析し、最後に共有参照を変更する (データをコンテナに追加するなど) コードを書いてからロックを解放するようなことは、通常ありません。その代わり、ロックは 共有リソース .

これは、クリティカルセクションの外側では内側よりもかなり多くの作業があることを意味するので、当然ながら、あるスレッドがクリティカルセクションの内側にいる可能性は比較的低く、したがって同時にロックを争うスレッドはほとんどないのです。もちろん、たまに2つのスレッドが同時にロックを取得しようとすることはありますが(もしこれが できなかった が発生した場合、ロックは必要ありません!)しかし、これはむしろquot;healthy"システムにおけるルールよりも例外的です。

このような場合、スピンロックは は非常に なぜなら、ロックの輻輳がない場合、スピンロック取得のオーバーヘッドは、コンテキスト スイッチの数百/数千サイクルやタイムスライスの残りを失う 1,000 ~ 2,000 万サイクルと比較して、わずか数十サイクルに過ぎないからです。

一方、混雑が激しい場合、またはロックが長時間保持される場合 (時にはどうしようもない場合もあります)、スピンロックは何も達成しないのに膨大な量の CPU サイクルを消費します。

この場合、セマフォ (またはミューテックス) がはるかに良い選択となります。 役に立つ タスクを実行することができるからです。あるいは、他のスレッドが何か有用なことを行っていない場合、オペレーティング システムが CPU をスロットルダウンし、熱を削減/エネルギーを節約することができます。

また、シングル コア システムでは、スピンロックはロックが混雑している場合には非常に非効率的です。スピンしているスレッドは、起こりえない状態変化 (解放するスレッドがスケジュールされるまでない、これは は起きない 待機中のスレッドが動作している間は起きないのです!)。したがって、与えられた を考えると、ロックの取得には最良のケースで約 1 1/2 のタイムスライスがかかります (解放するスレッドが次にスケジュールされるスレッドであると仮定しています) が、これはあまり良い動作ではありません。

4. どのように実装されているか

セマフォは、今日では通常、ラップされた sys_futex をラップします(オプションとして、数回試行した後に終了するスピンロックもあります)。

スピンロックは通常、アトミック操作を使用して実装され、オペレーティング システムによって提供されるものは何も使用しません。過去には、これは、コンパイラー イントリンシックまたは移植不可能なアセンブラー命令のいずれかを使用することを意味しました。一方、C++11 と C11 の両方は言語の一部としてアトミック操作を備えているため、証明可能な正しいロックフリー コードを書くことの一般的な難しさは別として、完全に移植可能で (ほぼ) 苦痛のない方法でロックフリー コードを実装することができるようになりました。