マルチスレッドについて読んだリソース全体を通して、ミューテックスはセマフォと比較してより頻繁に使用され、議論されています。私の質問は、いつミューテックスでセマフォを使用するのですか? Boost スレッドにセマフォが表示されません。それは、セマフォが最近あまり使われなくなったということですか?
私が理解している限り、セマフォを使用すると、リソースを複数のスレッドで共有できます。これは、それらのスレッドがリソースの読み取りのみを行い、書き込みを行わない場合にのみ可能です。これは正しいです?
マルチスレッドについて読んだリソース全体を通して、ミューテックスはセマフォと比較してより頻繁に使用され、議論されています。私の質問は、いつミューテックスでセマフォを使用するのですか? Boost スレッドにセマフォが表示されません。それは、セマフォが最近あまり使われなくなったということですか?
私が理解している限り、セマフォを使用すると、リソースを複数のスレッドで共有できます。これは、それらのスレッドがリソースの読み取りのみを行い、書き込みを行わない場合にのみ可能です。これは正しいです?
ミューテックスの一般的な使用例 (リソースへのアクセスを常に 1 つのスレッドのみに許可する) は、セマフォの場合の一般的な使用例よりもはるかに一般的です。しかし、セマフォは実際にはより一般的な概念です。ミューテックスは (ほぼ) セマフォの特殊なケースです。
典型的なアプリケーションは次のとおりです。 (たとえば) 5 つを超えるデータベース接続を作成したくない場合。ワーカー スレッドがいくつあっても、これらの 5 つの接続を共有する必要があります。または、N コア マシンで実行している場合は、特定の CPU/メモリを集中的に使用するタスクが同時に N を超えるスレッドで実行されないようにする必要がある場合があります (コンテキスト スイッチによるスループットの低下のみになるため)。およびキャッシュのスラッシング効果)。システムの残りの部分が枯渇しないように、CPU/メモリを集中的に使用する並列タスクの数を N-1 に制限することもできます。または、特定のタスクが大量のメモリを必要とするため、そのタスクの N 個を超えるインスタンスを同時に実行すると、ページングが発生することを想像してください。ここでセマフォを使用して、この特定のタスクのインスタンスが同時に N 個以上実行されないようにすることができます。
EDIT / PS:あなたの質問から「これは、それらのスレッドがリソースを読み取るだけで書き込みを行わない場合にのみ可能です。これは正しいですか?」そしてあなたのコメントは、リソースを変数またはストリームとして考えているように思えます。これらは読み取りまたは書き込みが可能で、一度に 1 つのスレッドだけが書き込むことができます。しないでください。これは、このコンテキストでは誤解を招きます。
資源は「水」のようなものと考えてください。水を使って食器を洗うことができます。水を使って食器を同時に洗うことができます。両方に十分な水があるので、そのために同期は必要ありません。必ずしも同じ水を使うとは限りません。(そして、水を「読み書き」することはできません。) しかし、水の総量は有限です。そのため、複数のパーティーが同時に食器を洗うことはできません。この種の同期は、セマフォで行われます。通常、水だけではなく、メモリ、ディスク容量、IO スループット、CPU コアなどの他の有限リソースを使用します。
ミューテックスとセマフォの違いの本質は、所有権の概念に関係しています。ミューテックスが取得されると、そのスレッドがミューテックスを所有していると見なされ、同じスレッドが後でミューテックスを解放してリソースを解放する必要があります。
セマフォの場合、セマフォをリソースを消費するものと考えてください。ただし、実際にはその所有権を取得するわけではありません。これは一般に、セマフォがスレッドによって所有されているのではなく、「空」であると呼ばれます。セマフォの特徴は、別のスレッドがセマフォを「満杯」状態に「満たす」ことができることです。
したがって、ミューテックスは通常、リソースの同時実行保護 (つまり、MUTual EXlusion) に使用され、セマフォはスレッド間のシグナリング (シップ間のセマフォ フラグのシグナリングなど) に使用されます。ミューテックス自体は実際にはシグナル伝達に使用できませんが、セマフォは使用できます。したがって、どちらを選択するかは、何をしようとしているのかによって異なります。
再帰的ミューテックスと非再帰的ミューテックスの違いをカバーする関連トピックの詳細については、こちらの別の回答を参照してください。
複数のスレッド (プロセス間またはプロセス内) によって共有される限られた数のリソースへのアクセスを制御するため。
私たちのアプリケーションでは、非常に重いリソースがあり、M 個のワーカー スレッドごとにリソースを割り当てたくありませんでした。ワーカー スレッドはジョブのほんの一部にリソースを必要とするため、複数のリソースを同時に使用することはめったにありませんでした。
そのため、これらのリソースを N 個割り当て、N に初期化されたセマフォの背後に配置しました。N 個を超えるスレッドがリソースを使用しようとすると、リソースが使用可能になるまでブロックされます。
Boost.Thread にはミューテックスと条件変数があります。したがって、純粋に機能の観点から、セマフォは冗長です[*]。ただし、それが省略されている理由かどうかはわかりません。
セマフォはより基本的なプリミティブで単純であり、より高速に実装される可能性がありますが、優先順位の逆転を回避する機能はありません。ポストの数が待機の数と適切な方法で「一致」することをクライアント コードで確認する必要があるため、条件変数よりも使用するのが難しいことはほぼ間違いありません。条件変数を使用すると、条件をチェックせずに実際に何もしないため、偽の投稿を容認するのは簡単です。
読み取りリソースと書き込みリソースは赤ニシンの IMO であり、ミューテックスとセマフォの違いとは何の関係もありません。カウンティング セマフォを使用すると、複数のスレッドが同時に同じリソースにアクセスする状況が発生する可能性があります。その場合、おそらく読み取り専用アクセスにする必要があります。shared_mutex
そのような状況では、代わりに Boost.Threadから使用できる場合があります。ただし、セマフォはミューテックスのようにリソースを保護するためのものではなく、あるスレッドから別のスレッドにシグナルを送信するためのものです。それらを使用して、リソースへのアクセスを制御できます。
これは、セマフォのすべての使用が読み取り専用リソースに関連している必要があるという意味ではありません。たとえば、バイナリ セマフォを使用して読み取り/書き込みリソースを保護できます。ただし、多くの場合、mutex を使用するとより良いスケジューリング動作が得られるため、これは良い考えではないかもしれません。
[*] 以下は、ミューテックスと条件変数を使用してカウンティング セマフォを実装する方法を大まかに示したものです。もちろん、共有セマフォを実装するには、共有ミューテックス/ condvar が必要です。
struct sem {
mutex m;
condvar cv;
unsigned int count;
};
sem_init(s, value)
mutex_init(s.m);
condvar_init(s.cv);
count = value;
sem_wait(s)
mutex_lock(s.m);
while (s.count <= 0) {
condvar_wait(s.cv, s.m);
}
--s.count;
mutex_unlock(s.m);
sem_post(s)
mutex_lock(s.m);
++s.count;
condvar_broadcast(s.cv)
mutex_unlock(s.m);
したがって、セマフォでできることは何でも、mutex と条件変数で行うことができます。ただし、必ずしも実際にセマフォを実装する必要はありません。
セマフォに関するいくつかの重要な情報を無視せずに、本当にあなたの質問に答える簡単な方法はないように感じます。人々はセマフォについて多くの本を書いているので、1 つまたは 2 つの段落の回答は役に立たないものです。人気のある本はセマフォの小さな本です...大きな本が好きではない人向けです:)。
これは、セマフォがどのように使用され、どのように使用されることを意図しているかについて、多くの詳細を説明するかなり長い記事です。
更新:
ダンは私の例のいくつかの間違いを指摘しました。
セマフォを使用する正しい方法を示す参考文献を次に示します
。 1. IBM の記事
2. シカゴ大学の講義
3. 最初に投稿した Netrino の記事。
4. 「チケットを売る」紙 + コード。
セマフォは、もともとプロセス間の同期のために考案されました。Windows は、セマフォのような WaitForMultipleObjects を使用します。Linux の世界では、最初の pthread 実装では、mutex をプロセス間で共有できませんでした。今、彼らはそうします。アトミック インクリメント (Windows のインターロック インクリメント) を軽量ミューテックスと共に破るという概念は、スレッドが CPU のスケジューリングの単位になった現在、最も実用的な実装です。インクリメントとロックが一緒 (セマフォ) である場合、ロックの取得/解放に時間がかかりすぎて、パフォーマンスとより良い同期構造のために現在行っているように、これら 2 つのユニット関数を分割することはできません。
私が理解している限りでは、セマフォは最近 IPC に強く関連する用語です。これは、保護された変数を多くのプロセスが変更できることを意味しますが、プロセス間およびこの機能は OS によってサポートされています。
通常、変数は必要なく、単純なミューテックスですべての要件がカバーされます。それでも変数が必要な場合は、おそらく自分でコーディングします-「変数+ミューテックス」でより多くの制御を取得します。
再開: 通常、シンプルさと制御のためにミューテックスを使用するため、マルチスレッドではセマフォを使用しません。IPC には、OS でサポートされており、プロセス同期メカニズムの正式名称であるため、セマフォを使用します。
大学でセマフォとミューテックスについて学んだことから、セマフォはより理論的なオブジェクトであり、ミューテックスはセマフォの1つの実装です。それを考慮すると、セマフォはより柔軟です。
Mutex は実装に大きく依存します。これらは、バイナリ ロックの目的で最適化されています。ミューテックスの通常の使用例は、バイナリ セマフォです。
一般に、バグのないマルチスレッド コードを作成しようとするときは、シンプルさが役立ちます。ミューテックスは、その単純さがセマフォの使用から生じる複雑なデッドロック シナリオを回避するのに役立つため、より多く使用されます。