条件付き変数とセマフォ


回答:


207

ロックは相互排除に使用されます。コードの一部がアトミックであることを確認したい場合は、コードをロックします。理論的にはバイナリセマフォを使用してこれを行うことができますが、それは特別なケースです。

セマフォと条件変数は、ロックによって提供される相互排除の上に構築され、共有リソースへの同期アクセスを提供するために使用されます。同様の目的で使用できます。

条件変数は、リソースが利用可能になるのを待つ間、ビジーな待機(条件を確認しながら繰り返しループする)を回避するために通常使用されます。たとえば、キュ​​ーが空になるまで先に進むことができないスレッド(または複数のスレッド)がある場合、ビジー待機アプローチは次のようにするだけです。

//pseudocode
while(!queue.empty())
{
   sleep(1);
}

この問題は、このスレッドに状態を繰り返しチェックさせることで、プロセッサ時間を浪費していることです。代わりに、リソースが使用可能であることをスレッドに通知するために通知できる同期変数がないのはなぜですか?

//pseudocode
syncVar.lock.acquire();

while(!queue.empty())
{
   syncVar.wait();
}

//do stuff with queue

syncVar.lock.release();

おそらく、キューから何かを引き出すスレッドがどこかにあるでしょう。キューが空の場合、それは呼び出しsyncVar.signal()て、スリープ状態にあるランダムなスレッドをウェイクアップできますsyncVar.wait()(または、通常、待機中のすべてのスレッドをウェイクアップするためのsignalAll()or broadcast()メソッドもあります)。

キューが空になるなど、1つの特定の条件で1つ以上のスレッドが待機している場合、通常はこのような同期変数を使用します。

セマフォも同様に使用できますが、利用可能なものの整数に基づいて利用可能と利用不可の共有リソースがある場合、セマフォがより適切に使用されると思います。セマフォは、プロデューサがリソースを割り当て、コンシューマがリソースを消費しているプロデューサ/コンシューマの状況に適しています。

あなたがソーダの自動販売機を持っていたかどうか考えてください。ソーダマシンは1つだけで、それは共有リソースです。マシンの在庫を維持する責任があるベンダー(プロデューサー)である1つのスレッドと、マシンからソーダを取り出したいバイヤー(コンシューマー)であるNのスレッドがあります。マシン内のソーダの数は、セマフォを駆動する整数値です。

ソーダマシンに到達するすべてのバイヤー(消費者)スレッドは、セマフォdown()メソッドを呼び出してソーダを取得します。これにより、マシンからソーダが取得され、使用可能なソーダの数が1つ減ります。使用可能なソーダがある場合、コードはdown()問題なくステートメントを通過し続けます。ソーダが使用できない場合、スレッドはここでスリープ状態になり、ソーダが再び使用可能になったとき(マシンにソーダがさらにあるとき)の通知を待ちます。

ベンダー(プロデューサー)スレッドは基本的に、ソーダマシンが空になるのを待っています。ベンダーから最後のソーダがマシンから取り出されると通知されます(1人以上の消費者がソーダの取り出しを待っている可能性があります)。ベンダーは、セマフォup()メソッドを使用してソーダマシンを補充し、使用可能なソーダの数を毎回インクリメントして、待機中のコンシューマスレッドに、より多くのソーダが使用可能であることを通知します。

同期変数のwait()およびsignal()メソッドは、セマフォのdown()およびup()操作内に隠される傾向があります。

確かに、2つの選択肢の間には重複があります。セマフォまたは条件変数(または条件変数のセット)の両方があなたの目的に役立つことができる多くのシナリオがあります。セマフォと条件変数はどちらも、相互排除を維持するために使用するロックオブジェクトに関連付けられていますが、スレッドの実行を同期するためにロックの上に追加の機能を提供します。どれがあなたの状況に最も意味があるかを見つけるのは、主にあなた次第です。

それは必ずしも最も技術的な説明ではありませんが、それが私の頭の中で理にかなっている方法です。


9
すばらしい回答です。他の回答から追加したいと思います。回答:セマフォは、実行中のスレッドの数を制御するために使用されます。リソースの固定セットがあります。リソースカウントは、スレッドが所有するたびに減少します。セマフォカウントが0に達すると、他のスレッドはリソースを取得できなくなります。スレッドは、リソース解放を所有する他のスレッドまでブロックされます。つまり、主な違いは、一度にリソースを取得できるスレッドの数です。Mutex-そのONE。セマフォ-そのDEFINED_COUNT(セマフォカウントと同じ数)
berkay 2014

10
単純なifではなく、なぜwhileループがあるのか​​を詳しく説明します:spurios wakeupと呼ばれるもの。このウィキペディアの記事を引用: 「これの理由の1つは、偽のウェイクアップです。つまり、条件変数を通知するスレッドがない場合でも、スレッドが待機状態から
起こさ

3
@VladislavsBurakovs良い点!ブロードキャストが利用可能なリソースよりも多くのスレッドを起動する場合にも役立ちます(たとえば、ブロードキャストは3つのスレッドを起動しますが、キューには2つのアイテムしかない)。
ブレントがコード

キューがいっぱいになるまで、回答に賛成票を入れたいと思います。このコードはセマフォcsc.villanova.edu/~mdamian/threads/PC.htm
Mohamad-Jaafar NEHME

3
@VladislavsBurakovs少し明確にするために、目覚めたばかりのスレッドに対して条件がまだ偽である可能性がある(誤ったウェイクアップが発生する)理由は、スレッドが条件をチェックする機会を得る前にコンテキストの切り替えがあった可能性があるためです。繰り返しになりますが、他のスケジュールされたスレッドがその条件を偽にしました。これは私が偽の目覚めのために知っている一つの理由です、もっとあるかどうかわかりません。
最大

52

内部の内容を明らかにしましょう。

条件付き変数は基本的に待機キューであり、ブロッキング待機操作とウェイクアップ操作をサポートします。つまり、スレッドを待機キューに入れてその状態をBLOCKに設定し、そこからスレッドを取得してその状態をREADYに設定できます。

条件変数を使用するには、他に2つの要素が必要です。

  • 条件(通常はフラグまたはカウンターをチェックすることで実装されます)
  • 状態を保護するミューテックス

プロトコルはその後、

  1. ミューテックスを取得する
  2. チェック状態
  3. 条件が真の場合はミューテックスをブロックして解放し、そうでない場合はミューテックスを解放する

セマフォは基本的に、カウンター+ミューテックス+待機キューです。また、外部依存なしでそのまま使用できます。ミューテックスまたは条件変数として使用できます。

したがって、セマフォは条件付き変数よりも洗練された構造として扱うことができますが、後者はより軽量で柔軟です。


mutexは条件変数と見なすことができ、その条件は保持されるかどうかです。
宏杰李

18

セマフォは、変数への排他的アクセスを実装するために使用できますが、同期のために使用することを目的としています。一方、ミューテックスには、相互排除に厳密に関連するセマンティクスがあります。リソースをロックしたプロセスだけが、リソースのロックを解除できます。

残念ながら、ミューテックスとの同期を実装することはできません。そのため、条件変数があります。また、条件変数を使用すると、ブロードキャストロック解除を使用して、待機中のすべてのスレッドを同時にロック解除できることに注意してください。これはセマフォでは実行できません。


9

セマフォと条件変数は非常によく似ており、ほとんど同じ目的で使用されます。ただし、1つを望ましいものにすることができる小さな違いがあります。たとえば、バリア同期を実装するためにセマフォを使用することはできませんが、条件変数が理想的です。

バリア同期とは、すべてのスレッドが、全員がスレッド関数の特定の部分に到達するまで待機する場合です。これは、バリアに到達したときに各スレッドによってデクリメントされた合計スレッドの値である静的変数を持つことによって実装できます。これは、最後のスレッドが到着するまで各スレッドをスリープさせたいことを意味します。セマフォはまったく逆のことを行います!セマフォを使用すると、各スレッドは実行を継続し、最後のスレッド(セマフォの値を0に設定します)はスリープ状態になります。

一方、条件変数は理想的です。各スレッドがバリアに到達すると、静的カウンターがゼロかどうかを確認します。そうでない場合は、条件変数の待機関数を使用してスレッドをスリープ状態に設定します。最後のスレッドがバリアに到達すると、カウンター値はゼロにデクリメントされ、この最後のスレッドは他のすべてのスレッドを起動する条件変数シグナル関数を呼び出します。


1

モニターの同期の下で条件変数をファイルします。私は一般的にセマフォとモニターを2つの異なる同期スタイルとして見ました。本質的に保持される状態データの量と、コードをモデル化する方法の点で、2つの間に違いがあります。しかし、実際には片方で解決できるが、もう片方では解決できない問題はありません。

私はモニターフォームに向けてコーディングする傾向があります。私が作業するほとんどの言語では、ミューテックス、条件変数、およびいくつかのバッキング状態変数が使用されます。しかし、セマフォも機能します。


2
「モニターフォーム」とは何かを説明した方がいいでしょう。
Steven Lu

0

mutexconditional variablesから継承されますsemaphore

  • の場合mutexsemaphoreは2つの状態を使用します:0、1
  • 以下のための 用途カウンター。condition variablessemaphore

彼らは構文糖のようなものです


C ++ stdライブラリでは、これらはすべて地区オブジェクトであり、すべてプラットフォーム固有のAPIを使用して実装されています。確かに、セマフォはシグナルされた回数のブロックを解除します。条件変数は複数回シグナルされますが、ブロックを解除するのは1回だけです。これが、wairがmutexをパラメーターとして取る理由です。
doron
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.