バイナリセマフォとミューテックスの違い


819

バイナリセマフォとミューテックスの間に違いはありますか、それとも本質的に同じですか?


11
これらは意味的には同じですが、実際には奇妙な違いに気づくでしょう(特にWindowsの場合)。
マイケル・フカラキス、2009年

5
@Michael Foukarakis:奇妙な違いは何ですか?
フィリップ

2
私は奇妙な表現が正しくなかったと思います。mutexは所有権をサポートし、場合によっては再入もサポートします。これはWindowsの場合です。さらに、WindowsのセマフォはEventオブジェクトの上に実装されていますが、これが実際にどのような意味を持つのかはわかりません。
Michael Foukarakis、2010


2
@philipxy「m」の代わりに「rn」をうまく隠しました。
Mooncrater

回答:


691

それらは同じものではありません。それらはさまざまな目的で使用されます!
どちらのタイプのセマフォもフル/空の状態であり、同じAPIを使用しますが、使用方法は大きく異なります。

相互排除セマフォ
相互排除セマフォは、共有リソース(データ構造、ファイルなど)を保護するために使用されます。

Mutexセマフォは、それを受け取るタスクによって「所有」されます。タスクBが現在タスクAが保持しているミューテックスをsemGiveしようとすると、タスクBの呼び出しはエラーを返し、失敗します。

mutexは常に次のシーケンスを使用します。

  -SemTake
  -重要なセクション
  -SemGive

以下に簡単な例を示します。

  スレッドAスレッドB
   ミューテックスを取る
     データにアクセスする
     ...ミューテックス<==をブロックします
     ...
   Mutexにアクセスデータを提供<==ブロック解除
                                  ...
                                ミューテックスを与える

バイナリセマフォ
バイナリセマフォは、まったく異なる質問に対応します。

  • タスクBは、何かが発生する(センサーが作動しているなど)のを待機しています。
  • センサートリップと割り込みサービスルーチンが実行されます。旅行のタスクを通知する必要があります。
  • タスクBが実行され、センサーがトリップするための適切なアクションを実行する必要があります。その後、待機に戻ります。

   Task A                      Task B
   ...                         Take BinSemaphore   <== wait for something
   Do Something Noteworthy
   Give BinSemaphore           do something    <== unblocks

バイナリセマフォでは、Bがセマフォを取得し、Aがセマフォを取得しても問題ないことに注意してください。
この場合も、バイナリセマフォはリソースをアクセスから保護していません。セマフォを与えて取るという行為は、基本的に切り離されています。
通常、同じバイナリセマフォに対してギブアンドテイクを行うことは、同じタスクにはほとんど意味がありません。


12
ミューテックスはバイナリセマフォよりも優れていませんか?誰かが実際に保持していないロックを解放しても意味がないからです。
Pacerier 2011

111
彼らは異なる目的を持っています。Mutexはリソースへの排他的アクセス用です。同期にはバイナリセマフォを使用する必要があります(つまり、「こんにちは、誰か!これが発生しました!」)。バイナリの「提供者」は、「受け手」がだれにでも、彼らが待っていたことが起こったことを通知するだけです。
Benoit

5
@Pacerierあなたは目的を混乱させています。ミューテックスは、重要な領域を保護することを目的としています。正解ですが、バイナリセマフォを使用しても意味がありません。回答を更新して、それぞれの目的を説明します。
Benoit

4
@Benoitでは、タスクBはロックの解放を通知するためにタスクBが本質的にデータ構造での操作の順序を確実に確認するので、Mutexは原子性とバイナリセマフォの順序パースペクティブに使用されていると言えますか?
abhi 2014

1
@abhiこれは、Mutexについて見るのに良い方法です。ただし、OSによっては、バイナリセマフォで複数の受信者を待機させることができます。その場合、クライアントの1つだけがバイナリsemを取得します。他の人は次のものを待ちます。受け取る順序は既知ですか、それとも保証されますか?OSに依存します。
ブノワ

446
  • ミューテックスはのみによって解除することができ、それを獲得したスレッド
  • バイナリセマフォをシグナリングすることができる任意のスレッドによって(またはプロセス)。

そのため、セマフォは、プロデューサー/コンシューマーなどのいくつかの同期問題に適しています。

Windowsでは、バイナリセマフォはミューテックスよりもイベントオブジェクトに似ています。


34
Mutex can be released only by thread that had acquired it-単純なpthread_mutexベースのプログラムで試したところ、メインスレッドでロックされているミューテックスをスレッドがロック解除できる
デイジー

15
@ warl0ck pthread_mutex_lockのmanページにあるようにlinux.die.net/man/3/pthread_mutex_lock: "ミューテックスタイプがPTHREAD_MUTEX_ERRORCHECKの場合、エラーチェックが提供されます。スレッドが持っているミューテックスをロック解除しようとするとロックされていないか、ロックされていないミューテックスの場合、エラーが返されます。」
2013年

47
@ warl0ckご覧くださいstackoverflow.com/a/5492499/385064高速ミューテックス、再帰的ミューテックス、およびエラーチェックミューテックス「のPthreadは、ミューテックスの3種類があります。パフォーマンス上の理由から、このエラーをチェックしない高速ミューテックスを使用しました。Linuxでエラーチェックミューテックスを使用すると、期待どおりの結果が得られます。
FrostNovaZzz 2013年

1
このコードでは、同期のためにもミューテックスを使用しました。ミューテックスをロックするスレッドは、ミューテックスを再度ロックしようとしました。その後、ミューテックスはブロックされた状態になります。これまでに確認したことは、これを別のスレッドからロック解除できることです。 2つの間の同期。私たちはposix標準のみを使用しています。したがって、mutexとバイナリセマフォの主な違いは曖昧に見えます。
achoora 2016

1
@achooraセマフォを同期専用にするのは間違っていることに同意します。実際には、すべてのミューテックス、バイナリセマフォ、バリア、パイプラインは、同期の異なるパターンです。デザインの観点では、ミューテックスは状態パターンに似ており、状態によって選択されるアルゴリズムが状態を変更できます。バイナリセマフォは、外部アルゴリズムが状態を変更し、最終的に実行するように選択されたアルゴリズム/戦略を変更できる戦略パターンに似ています。
シュヴァ

442

トイレの例は楽しいアナロジーです:

ミューテックス:

トイレの鍵です。一度に一人の人が鍵を手に入れることができます-トイレを占有します-。終了すると、その人はキュー内の次の人に鍵を渡します(解放します)。

公式には、「Mutexeは通常、複数のスレッドで同時に実行できない再入可能コードのセクションへのアクセスをシリアル化するために使用されます。ミューテックスオブジェクトは、制御されたセクションに1つのスレッドのみを許可し、他のスレッドにアクセスを試行させます。そのセクションから、最初のスレッドが終了するまで待機します。」参照:Symbian開発者ライブラリ

(ミューテックスは実際には値1のセマフォです。)

セマフォ:

無料の同じトイレの鍵の数です。例として、鍵と鍵が同じトイレが4つあるとします。セマフォの数-キーの数-は最初は4に設定され(4つのトイレはすべて無料)、人が入るにつれてカウント値は減少します。すべてのトイレがいっぱいの場合、つまり 空きキーが残っていないため、セマフォカウントは0です。1人がトイレを離れると、セマフォが1(1つのフリーキー)に増加し、キュー内の次の人に渡されます。

公式に:「セマフォは共有リソースの同時ユーザー数を最大数に制限します。スレッドはリソースへのアクセスを要求でき(セマフォを減らします)、リソースの使用が終了したことを通知できます(セマフォを増やします)。 」参照:Symbian開発者ライブラリ


234
...しかし、これはセマフォとミューテックスの比較です。バイナリについて質問されました。
Roman Nikitchenko

24
davidの発言は正しいですが、質問に対する答えではありません。Mladen Jankovicの回答は、「バイナリセマフォ」と「mutex」を区別するためのポイントである質問に対する回答です。
Ajeet Ganga 2011

13
残念ながら、この間違った答えは@Benoitによる最良の答えよりも投票数が多い
NeonGlow

6
この答えは誤解を招くものです。バイナリセマフォとのみ比較する必要があります。
Hemanth 14年

3
これはまた、カウントセマフォを使用して共有リソースを保護する場合の問題も示しています。キーが実際に同じで、トイレがキーを使用してロックが解除されており、キュービクルの使用を分散する他のメカニズムがない場合:(1)最初のユーザーは、最初のキュービクルのロックを解除して入力し、使用を開始します。(2)次のユーザーが最初のキュービクルのロックを解除し、入力し、使用を開始します...
Technophile

151

トピックに関する素晴らしい記事:

パート2から:

ミューテックスはバイナリセマフォの原則に似ていますが、所有権の原則という大きな違いがあります。所有権とは、タスクがmutexをロック(取得)すると、それだけがロック解除(解放)できるという単純な概念です。タスクがロックしていない(つまり所有していない)ミューテックスをロック解除しようとすると、エラー条件が発生し、最も重要なことには、ミューテックスはロック解除されません。相互排除オブジェクトが所有権を持たない場合、それが何と呼ばれるかに関係なく、それはミューテックスではありません。


リンクをありがとう、そこの説明は素晴らしいです。リンクが変更されました:feabhas.com/blog/2009/09/...(使用<前のページと次の>他の二つの記事に移動する。
アーロンH.

@Aaronリンクを修正しました
Maygarden裁判官、10年

注-所有権がないため、オペレーティングシステムが優先順位の逆転を回避することもできません。このため、プロデューサー/コンシューマーアーキテクチャのセマフォとは対照的に、通常は条件変数を使用します。
kgriffs

1
+1敵の優れた記事へのリンク。「what-it-is」と「what-it-does」computeing.llnl.gov/tutorials/pthreadsを使用してセマフォとミューテックスを説明する最高の記事。 この記事を舞台裏のリファレンスとして使用しましたが、技術的にすべてについて説明しています。 mutex /条件文およびセマフォ/バリア/リーダーライターのようにその上に構築された他の構成要素。ただし、構成要素が直面する問題について明示的かつ簡潔な場所はありません。要するに参考です。:)
Ajeet Ganga 2011

他の答えよりも簡単に理解できます。
BinaryTreeee 2018

101

上記の答えはどれも混乱を解消しないので、ここに私の混乱を解消したものがあります。

厳密に言うと、mutexはリソースへのアクセスを同期するために使用されるロックメカニズムです。mutexを取得できるのは、1つのタスク(OS抽象化に基づくスレッドまたはプロセスにすることができます)のみです。つまり、mutexに関連付けられた所有権が存在し、所有者だけがロック(mutex)を解放できます。

セマフォはシグナリングメカニズムです(「完了しました。続行できます」のような信号です)。たとえば、携帯電話で曲を聴いているとき(それを1つのタスクと想定)、友人があなたに電話をかけると同時に、割り込みがトリガーされ、割り込みサービスルーチン(ISR)がコール処理タスクにウェイクアップするようシグナルを送ります。 。

出典:http : //www.geeksforgeeks.org/mutex-vs-semaphore/


42

同期のセマンティクスは大きく異なります。

  • mutexは、特定のリソースへのアクセスのシリアル化を許可します。つまり、複数のスレッドが一度に1つずつロックを待機し、前述のように、スレッドはロックが完了するまでロックを所有します。この特定のスレッドだけがロックを解除できます。
  • バイナリセマフォは、値0および1のカウンタです。タスクがsem_postを実行するまでタスクはブロックします。セマフォは、リソースが利用可能であることを通知し、リソースが利用可能であると通知されるまで待機するメカニズムを提供します。

そのような一つのタスクからタスクおよびトラフィックとしてセマフォに渡されるトークンとしてミューテックスを見ることができるように赤色光(それは信号が進行することができることを誰かに)。


23

理論的なレベルでは、それらは意味的に違いはありません。セマフォを使用してミューテックスを実装することも、その逆も可能です(例についてはこちらを参照)。実際には、実装は異なり、わずかに異なるサービスを提供します。

(それらを取り巻くシステムサービスの点で)実際的な違いは、ミューテックスの実装がより軽量な同期メカニズムであることを目的としていることです。oracle-speakでは、ミューテックスはラッチと呼ばれ、セマフォは待機と呼ばれます

最下位レベルでは、ある種のアトミックテストと設定メカニズムを使用します。これは、メモリ位置の現在の値を読み取り、何らかの条件を計算し、その位置で、割り込みできない単一の命令で値を書き込みます。つまり、ミューテックスを取得して、他の誰かがあなたの前に持っていたかどうかをテストすることができます。

典型的なミューテックスの実装には、テストと設定の命令を実行し、他に何かがミューテックスを設定したかどうかを評価するプロセスまたはスレッドがあります。ここでの重要な点は、スケジューラとの相互作用がないため、誰がロックを設定したのかわかりません(気にしない)。次に、タイムスライスをあきらめて、タスクが再スケジュールされたときに再試行するか、スピンロックを実行します。スピンロックは次のようなアルゴリズムです。

Count down from 5000:
     i. Execute the test-and-set instruction
    ii. If the mutex is clear, we have acquired it in the previous instruction 
        so we can exit the loop
   iii. When we get to zero, give up our time slice.

保護されたコード(クリティカルセクションと呼ばれます)の実行が終了したら、mutex値をゼロまたは「クリア」を意味する値に設定します。複数のタスクがミューテックスを取得しようとしている場合、ミューテックスが解放された後にたまたまスケジュールされている次のタスクがリソースにアクセスします。通常、ミューテックスを使用して、同期されたリソースを制御します。このリソースでは、通常、共有データ構造を更新するために、非常に短い期間だけ排他アクセスが必要です。

セマフォは、(通常はミューテックスを使用して)同期されたデータ構造であり、カウントと、ミューテックスライブラリよりも少し深くスケジューラとやり取りするいくつかのシステムコールラッパーを持っています。セマフォはインクリメントおよびデクリメントされ、他の準備ができるまでタスクをブロックするために使用されます。この簡単な例については、プロデューサー/コンシューマーの問題を参照してください。セマフォはある値に初期化されます。バイナリセマフォは、セマフォが1に初期化される特殊なケースです。セマフォにポストすると、待機中のプロセスが起動します。

基本的なセマフォアルゴリズムは次のようになります。

(somewhere in the program startup)
Initialise the semaphore to its start-up value.

Acquiring a semaphore
   i. (synchronised) Attempt to decrement the semaphore value
  ii. If the value would be less than zero, put the task on the tail of the list of tasks waiting on the semaphore and give up the time slice.

Posting a semaphore
   i. (synchronised) Increment the semaphore value
  ii. If the value is greater or equal to the amount requested in the post at the front of the queue, take that task off the queue and make it runnable.  
 iii. Repeat (ii) for all tasks until the posted value is exhausted or there are no more tasks waiting.

バイナリセマフォの場合、2つのセマフォの主な実用的な違いは、実際のデータ構造を取り巻くシステムサービスの性質です。

編集:エヴァンが正しく指摘したように、スピンロックはシングルプロセッサマシンの速度を低下させます。シングルプロセッサでは、ミューテックスを保持するプロセスが別のタスクの実行中にmutexをリセットすることはないため、マルチプロセッサボックスでのみスピンロックを使用します。スピンロックは、マルチプロセッサアーキテクチャでのみ役立ちます。


1
ミューテックスをスピンロックで実装することは一般的な習慣ではないと思います。Uni-procマシンでは、これはパフォーマンスにとって絶対にひどいものです。
エヴァンテラン

通常は、マルチプロセッサシステムでのみスピンロックを使用します。
ConcernedOfTunbridgeWells

SMPでも、数回スピンした後、OSが支援するスリープ/スリープ解除にフォールバックします。(たとえば、Linux futexシステムコールは、低レイテンシのユーザースペースミューテックス/セマフォの実装を支援するために存在します。en.wikipedia.org / wiki / Futex)競合なしの高速パスで、またはリソースがすぐに利用可能になった場合、オーバーヘッドが発生することはありませんシステムコール。しかし、数マイクロ秒以上ビジー待機(スピニング)を費やすことはありません。もちろん、スピンループバックオフと待機のパラメーターのチューニングはハードウェアとワークロードに依存しますが、通常、標準ライブラリには適切な選択肢があります。
Peter Cordes

19

ミューテックスとセマフォは同期プリミティブとして使用されますが、それらの間には大きな違いがあります。mutexの場合、mutexをロックまたは取得したスレッドのみがmutexをロック解除できます。セマフォの場合、セマフォで待機しているスレッドに別のスレッドからシグナルを送ることができます。一部のオペレーティングシステムは、プロセス間のミューテックスとセマフォの使用をサポートしています。通常、使用は共有メモリで作成されます。


「別のスレッドからシグナルを送ることができる」という意味は、例を挙げてください。
ミャンジュ

15

ミューテックス:クリティカルセクションスレッドT1がアクセスしたい場合、以下の手順に従います。T1:

  1. ロック
  2. 重要なセクションを使用
  3. ロックを解除

バイナリセマフォ:シグナル待機とシグナルに基づいて機能します。wait(s)は "s"値を1ずつ減らします。通常、 "s"値は値 "1"で初期化され、信号は "s"値を1つ増やします。「s」値が1の場合、クリティカルセクションを使用していないことを意味し、値が0の場合、クリティカルセクションが使用されていることを意味します。スレッドT2がクリティカルセクションを使用している場合、以下の手順に従います。T2:

  1. wait(s)//最初のs値は、waitを呼び出した後の値で、値が1減少します。つまり0
  2. クリティカルセクションを使用
  3. signal(s)//これでs値が増加し、1になります

MutexとBinaryセマフォの主な違いは、スレッドがクリティカルセクションをロックした場合、Mutextにあり、他のスレッドはクリティカルセクションをロック解除する必要はありませんが、バイナリセマフォの場合、1つのスレッドがwait(s)関数を使用してクリティカルセクションをロックした場合、値「s」の値が「0」になり、「s」の値が1になるまで誰もアクセスできませんが、他のスレッドがシグナルを呼び出して「s」の値が1になり、他の関数がクリティカルセクションを使用できるようになったとします。したがって、バイナリセマフォスレッドには所有権がありません。


12

Windowsでは、ミューテックスとバイナリセマフォには2つの違いがあります。

  1. mutexは、所有権を持つスレッド、つまり以前にWait関数を呼び出した(または作成時に所有権を取得した)スレッドによってのみ解放できます。セマフォはどのスレッドでも解放できます。

  2. スレッドは、ブロックせずにmutexで待機関数を繰り返し呼び出すことができます。ただし、セマフォを解放せずにバイナリセマフォで待機関数を2回呼び出すと、スレッドはブロックされます。


4
いい答えです。#2では、再帰的なmutexを記述しています-すべてのmutexが必ずしも再帰的であるとは限りません。例:cs.wustl.edu/~schmidt/ACE.FAQ.html#Q14
Dan

10

明らかにmutexを使用して、同時に別のスレッドからアクセスされる1つのスレッドのデータをロックします。呼び出したばかりlock()で、データにアクセスしていると仮定します。これは、他のスレッド(または同じスレッドコードの別のインスタンス)が同じミューテックスによってロックされた同じデータにアクセスすることを期待しないことを意味します。つまり、別のスレッドインスタンスで実行されている同じスレッドコードである場合、ロックをヒットすると、lock()そこで制御フローをブロックする必要があります。これは、同じデータにアクセスし、同じミューテックスによってロックされている別のスレッドコードを使用するスレッドに適用されます。この場合、まだデータにアクセスしている最中であり、ミューテックスのロック解除に到達するまでにさらに15秒かかる場合があります(ミューテックスロックでブロックされている他のスレッドのブロックが解除され、コントロールがデータにアクセスします)。何らかの犠牲を払って、別のスレッドが同じミューテックスをロック解除して、ミューテックスロックですでに待機(ブロッキング)しているスレッドがブロックを解除してデータにアクセスできるようにしますか?私がここで言っていることをあなたが理解したことを願っていますか?ごとに、普遍的な定義に同意しました!、

  • 「ミューテックス」では、これは起こり得ません。他のスレッドはあなたのスレッドのロックを解除できません
  • 「バイナリセマフォ」では、これが発生する可能性があります。他のスレッドは、スレッドのロックを解除できます

したがって、ミューテックスの代わりにバイナリセマフォを使用することに非常にこだわっている場合は、ロックとロック解除の「スコープ」に非常に注意する必要があります。つまり、すべてのロックにヒットするすべての制御フローは、ロック解除の呼び出しをヒットする必要があります。また、「最初のロック解除」ではなく、常に「最初のロック」である必要があります。


10

Mutexは「ロックメカニズム」に使用されます。一度に1つのプロセスが共有リソースを使用できます

一方

セマフォは、「信号メカニズム」に使用されます。


9

神話:

「バイナリセマフォとミューテックスは同じ」または「値1のセマフォはミューテックスである」という記事のカップルによると、他のスレッドからセマフォに信号を送ることができる一方で、ミューテックスはそれを取得したスレッドによってのみ解放できる

キーポイント:

•スレッドは複数のロックを取得できます(Mutex)。

•mutexは、その再帰的mutexの場合にのみ複数回ロックできます。ここで、mutexのロックとロック解除は同じでなければなりません。

•すでにミューテックスをロックしていたスレッドがミューテックスを再度ロックしようとすると、そのミューテックスの待機リストに入り、デッドロックが発生します。

•バイナリセマフォとミューテックスは似ていますが、同じではありません。

•Mutexは、それに関連付けられている保護プロトコルのため、コストのかかる操作です。

•mutexの主な目的は、アトミックアクセスまたはリソースのロックを達成することです


8

A ミューテックスは、単一の共有リソースへのアクセスを制御します。これは、そのリソースへのアクセスを取得()し、完了時にリリース()する操作を提供します。

A セマフォは、リソースの共有プールへのアクセスを制御します。これは、プール内のリソースの1つが使用可能になるまでWait()、およびプールに戻されたときにSignal()への操作を提供します。

セマフォが保護するリソースの数が1より大きい場合、それはカウントセマフォと呼ばれます。1つのリソースを制御する場合は、ブールセマフォと呼ばれます。ブールセマフォはミューテックスと同等です。

したがって、セマフォはミューテックスよりも高いレベルの抽象化です。ミューテックスはセマフォを使用して実装できますが、その逆はできません。


6

変更された質問は-「Linux」でのミューテックスと「バイナリ」セマフォの違いは何ですか?

回答:違いは次のとおりです– i)スコープ– mutexのスコープは、それを作成し、スレッドの同期に使用されるプロセスアドレス空間内にあります。一方、セマフォはプロセス空間全体で使用できるため、プロセス間同期に使用できます。

ii)Mutexはセマフォよりも軽量で高速です。Futexはさらに高速です。

iii)mutexは、同じスレッドが同じ回数解放できるという条件で、複数回正常に取得できます。取得しようとする他のスレッドはブロックされます。セマフォの場合、同じプロセスが再度取得しようとすると、一度しか取得できないためブロックされます。


i)間違っています。ii)ソース?iii)場合によります。
curiousguy

6

バイナリセマフォとミューテックスの違い:OWNERSHIP: セマフォは、現在の所有者以外からでも通知(ポスト)できます。所有者ではありませんが、他のどのスレッドからでも投稿できます。

セマフォは処理中のパブリックプロパティであり、所有者以外のスレッドから簡単に投稿できます。この違いを太字でマークしてください。


5

ミューテックスはクリティカル領域のブロックで機能しますが、セマフォはカウントで機能します。


5

http://www.geeksforgeeks.org/archives/9102 で詳細に議論されています。

Mutexリソースへのアクセスを同期するために使用されるロックメカニズムです。 Semaphore信号メカニズムです。

プログラマーがmutexの代わりにバイナリセマフォを使用するかどうかは、プログラマ次第です。


4

mutexに所有者がいるという事実は別として、2つのオブジェクトは異なる使用法のために最適化される場合があります。mutexは、短時間だけ保持されるように設計されています。これに違反すると、パフォーマンスが低下し、スケジュールが不当になる可能性があります。たとえば、別のスレッドがすでにブロックされている場合でも、実行中のスレッドはmutexの取得を許可される場合があります。セマフォはより公平性を提供するか、いくつかの条件変数を使用して公平性を強制することができます。


セマフォに対して公平性が保証されているが、ミューテックスに対しては保証されていない具体的なケースはどれですか?
curiousguy

1
POSIXには、sem_post()for SCHED_FIFOおよびSCHED_RR(これらは両方ともデフォルトではありません)によって起こされるスレッドの特定の要件があります。優先順位が最も高いスレッド、同じ優先順位のスレッドが複数ある場合は、最も長く待機しているスレッド。OpenSolarisは、通常のスケジューリングであっても、このFIFOルールにある程度従います。glibcとFreeBSDの場合、基本的なミューテックスのロック解除(つまり、優先保護や優先継承ではない)とセマフォのポストは基本的に同じで、オブジェクトをロック解除としてマークし、待機中のスレッドがある場合は、カーネルを呼び出してスレッドを起動します。
ジル

4

Windowsでの違いは次のとおりです。 MUTEX:待機を正常に実行するプロセスはシグナルを実行する必要があり、その逆も同様です。バイナリセマフォ:セマフォで異なるプロセスが待機またはシグナル操作を実行できます。


4

バイナリセマフォはミューテックスとして使用できますが、ミューテックスは、ミューテックスをロックしたプロセスだけがロック解除することになっているという点で、より具体的なユースケースです。この所有権の制約により、以下に対する保護を提供できます。

  • 偶発的なリリース
  • 再帰的なデッドロック
  • タスクデスデッドロック

これらの制約は速度を低下させるため、常に存在するとは限りません。コードの開発中に、これらのチェックを一時的に有効にすることができます。

たとえば、ミューテックスでエラーチェック属性を有効にすることができます。EDEADLK同じものを2回ロックしようとしたEPERM場合、および自分のものではないミューテックスをロック解除した場合、ミューテックスのエラーチェックは戻ります。

pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init (&mutex, &attr);

初期化したら、これらのチェックを次のようにコードに配置できます。

if(pthread_mutex_unlock(&mutex)==EPERM)
 printf("Unlock failed:Mutex not owned by this thread\n");

4

上記の投稿を読んだ後、コンセプトは私には明らかでした。しかし、いくつかの疑問が残りました。それで、私はこの小さなコードを書きました。

セマフォを使わずに渡そうとすると、それが通り抜けます。ただし、mutexを取得せずに指定しようとすると失敗します。これをWindowsプラットフォームでテストしました。USE_MUTEXを有効にして、MUTEXを使用して同じコードを実行します。

#include <stdio.h>
#include <windows.h>
#define xUSE_MUTEX 1
#define MAX_SEM_COUNT 1

DWORD WINAPI Thread_no_1( LPVOID lpParam );
DWORD WINAPI Thread_no_2( LPVOID lpParam );

HANDLE Handle_Of_Thread_1 = 0;
HANDLE Handle_Of_Thread_2 = 0;
int Data_Of_Thread_1 = 1;
int Data_Of_Thread_2 = 2;
HANDLE ghMutex = NULL;
HANDLE ghSemaphore = NULL;


int main(void)
{

#ifdef USE_MUTEX
    ghMutex = CreateMutex( NULL, FALSE, NULL);
    if (ghMutex  == NULL) 
    {
        printf("CreateMutex error: %d\n", GetLastError());
        return 1;
    }
#else
    // Create a semaphore with initial and max counts of MAX_SEM_COUNT
    ghSemaphore = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
    if (ghSemaphore == NULL) 
    {
        printf("CreateSemaphore error: %d\n", GetLastError());
        return 1;
    }
#endif
    // Create thread 1.
    Handle_Of_Thread_1 = CreateThread( NULL, 0,Thread_no_1, &Data_Of_Thread_1, 0, NULL);  
    if ( Handle_Of_Thread_1 == NULL)
    {
        printf("Create first thread problem \n");
        return 1;
    }

    /* sleep for 5 seconds **/
    Sleep(5 * 1000);

    /*Create thread 2 */
    Handle_Of_Thread_2 = CreateThread( NULL, 0,Thread_no_2, &Data_Of_Thread_2, 0, NULL);  
    if ( Handle_Of_Thread_2 == NULL)
    {
        printf("Create second thread problem \n");
        return 1;
    }

    // Sleep for 20 seconds
    Sleep(20 * 1000);

    printf("Out of the program \n");
    return 0;
}


int my_critical_section_code(HANDLE thread_handle)
{

#ifdef USE_MUTEX
    if(thread_handle == Handle_Of_Thread_1)
    {
        /* get the lock */
        WaitForSingleObject(ghMutex, INFINITE);
        printf("Thread 1 holding the mutex \n");
    }
#else
    /* get the semaphore */
    if(thread_handle == Handle_Of_Thread_1)
    {
        WaitForSingleObject(ghSemaphore, INFINITE);
        printf("Thread 1 holding semaphore \n");
    }
#endif

    if(thread_handle == Handle_Of_Thread_1)
    {
        /* sleep for 10 seconds */
        Sleep(10 * 1000);
#ifdef USE_MUTEX
        printf("Thread 1 about to release mutex \n");
#else
        printf("Thread 1 about to release semaphore \n");
#endif
    }
    else
    {
        /* sleep for 3 secconds */
        Sleep(3 * 1000);
    }

#ifdef USE_MUTEX
    /* release the lock*/
    if(!ReleaseMutex(ghMutex))
    {
        printf("Release Mutex error in thread %d: error # %d\n", (thread_handle == Handle_Of_Thread_1 ? 1:2),GetLastError());
    }
#else
    if (!ReleaseSemaphore(ghSemaphore,1,NULL) )      
    {
        printf("ReleaseSemaphore error in thread %d: error # %d\n",(thread_handle == Handle_Of_Thread_1 ? 1:2), GetLastError());
    }
#endif

    return 0;
}

DWORD WINAPI Thread_no_1( LPVOID lpParam ) 
{ 
    my_critical_section_code(Handle_Of_Thread_1);
    return 0;
}


DWORD WINAPI Thread_no_2( LPVOID lpParam ) 
{
    my_critical_section_code(Handle_Of_Thread_2);
    return 0;
}

セマフォが「リソースを使用して行われる」ことを通知できるという事実自体が、リソースを所有していない場合でも、セマフォの場合、所有とシグナリングの間には非常に疎結合があると思います。


他の回答を読んだ場合、「所有権」の概念は、セマフォではなく、ミューテックスでのみ意味があることは明らかです。セマフォは、データのチャンクの処理が完了したことを他のスレッドに知らせるスレッドなどに使用できます。結果を読み取る準備ができています。
Peter Cordes

2

機密コードとデータを保護するためにミューテックスが使用され、同期にはセマフォが使用されます。機密コードを保護することで実際に使用することもできますが、操作Vによって他のスレッドによる保護を解放するリスクがある可能性があります。バイセマフォとミューテックスの違いは所有権です。たとえば、トイレによって、ミューテックスはトイレに入ることができ、ドアをロックできるようなものです。男が降りるまで他の誰も入ることができません。バイセマフォは、そのようなものですトイレとドアをロックしますが、誰かが管理者にドアを開けるように要求することで入ることができるのは、とんでもないことです。


2

ミューテックス

ミューテックスは通常、複数のスレッドで同時に実行できない再入可能コードのセクションへのアクセスをシリアル化するために使用されます。ミューテックスオブジェクトでは、1つのスレッドのみが制御されたセクションに入ることができ、そのセクションにアクセスしようとする他のスレッドは、最初のスレッドがそのセクションから出るまで待機する必要があります。意図しない副作用。異なる優先順位で動作し、ミューテックスを介して調整する2つのRTOSタスクは、優先順位を逆転させる機会を生み出します。Mutexはユーザー空間で動作します

セマフォ

セマフォは信号メカニズムです。セマフォは、共有リソースの同時ユーザーの数を最大数に制限します。スレッドは、リソースへのアクセスを要求し(セマフォをデクリメント)、リソースの使用が終了したことを通知できます(セマフォをインクリメント)。これにより、多くのスレッドが共有リソースにアクセスできます。セマフォの正しい使用は、あるタスクから別のタスクへのシグナリング用です。セマフォは、割り込みサービスルーチン(ISR)からタスクへのシグナリングにも使用できます。セマフォのシグナリングはノンブロッキングRTOSの動作であり、したがってISRセーフです。この手法により、エラーが発生しやすいタスクレベルで割り込みを無効にする必要がなくなります。これはカーネル空間で機能します


1

答えはターゲットOSによって異なります。たとえば、私が精通している少なくとも1つのRTOS実装では、すべてが同じスレッドコンテキスト内にある限り、単一のOSミューテックスに対して複数の順次「取得」操作を許可します。別のスレッドがmutexを取得できるようにするには、複数のgetを同数のputで置き換える必要があります。 これは、スレッドコンテキストに関係なく、一度に1つのgetのみが許可されるバイナリセマフォとは異なります。

このタイプのミューテックスの背後にある考え方は、一度に1つのコンテキストのみがデータを変更できるようにすることでオブジェクトを保護することです。スレッドがミューテックスを取得し、オブジェクトをさらに変更する関数を呼び出した場合(および独自の操作の周りにプロテクターミューテックスを取得/配置した場合)でも、操作はすべて単一のスレッドで発生するため、安全です。

{
    mutexGet();  // Other threads can no longer get the mutex.

    // Make changes to the protected object.
    // ...

    objectModify();  // Also gets/puts the mutex.  Only allowed from this thread context.

    // Make more changes to the protected object.
    // ...

    mutexPut();  // Finally allows other threads to get the mutex.
}

もちろん、この機能を使用するときは、1つのスレッド内のすべてのアクセスが本当に安全であることを確認する必要があります。

このアプローチがどれほど一般的であるのか、または私がよく知っているシステムの外部に適用されるのかどうかはわかりません。この種のミューテックスの例については、ThreadX RTOSを参照してください。


2
あなたが話している種類のミューテックスは「再帰的ミューテックス」と呼ばれ、遅く、悪いデザインを促進する傾向があるため、避ける必要があります(David Butenhof:zaval.org/resources/library/butenhof1.htmlを参照)
gaspard

同意した。この特定のOSでは、コードが「相互排除」用であり、参照カウントではないことを明確にしたい場合にmutexサービスを使用しますが、醜い巻き戻しを恐れて再帰機能を使用しません。それでも、質問のコンテキストでは、これは「ミューテックス」と「バイナリセマフォ」の重要な違いです。
Casey Barker

1

mutexは、セマフォとは異なり、所有権を持っています。mutexのスコープ内のスレッドは、ロック解除されたmutexを取得し、コードの同じクリティカルセクションへのアクセスをロックできますが、mutexをロックしたスレッドのみロックを解除する必要があります。


所有権とは何ですか?mutexを取得するコンテキストは、それを取得解除することしかできないことを意味します。
Raulp、2012年

1

ここで多くの人々が述べたように、ミューテックスは重要なコード(別名クリティカルセクション)を保護するために使用されます。ミューテックスを取得(ロック)し、クリティカルセクションに入り、ミューテックスをすべて解放(ロック解除)します

セマフォを使用しているときに、別のスレッド(スレッドBなど)がタスクを完了するまでスレッドをセマフォ(スレッドAなど)で待機させ、スレッドAのセマフォを待機を停止してそのタスクを続行するように設定できます。


1

最良のソリューション

唯一の違いは

1.ミューテックス->ロックとロック解除は、ミューテックスをロックするスレッドの所有権の下にあります。

2.セマフォ->所有権なし。1つのスレッドがsemwait(s)を呼び出す場合、他のスレッドはsempost(s)を呼び出してロックを解除できます。


1

ミューテックス

最近まで、カーネルでスリープ状態のロックはセマフォだけでした。セマフォのほとんどのユーザーは、カウントを1にしてセマフォをインスタンス化し、それらを相互排他ロック(スピンロックのスリープバージョン)として扱いました。残念ながら、セマフォは汎用的であり、使用上の制約はありません。これにより、カーネルとユーザー空間の間の複雑なダンスなど、あいまいな状況での排他的アクセスの管理に役立ちます。しかし、これはまた、単純なロックは実行が困難であることを意味し、適用されるルールがないため、あらゆる種類の自動デバッグや制約の適用が不可能になります。より単純なスリープロックを求めて、カーネル開発者はミューテックスを導入しました。はい、あなたが今慣れているように、それは紛らわしい名前です。明確にしましょう。「mutex」という用語は、相互排他を強制するスリープ状態のロックを指す総称です。使用回数が1のセマフォなど。最近のLinuxカーネルでは、固有名詞「mutex」も相互排除を実装する特定のタイプのスリープロックになりました。つまり、mutexはmutexです。

ミューテックスのシンプルさと効率は、セマフォが必要とするものに加えて、ミューテックスがユーザーに課す追加の制約に由来しています。Dijkstraの元の設計に従って最も基本的な動作を実装するセマフォとは異なり、mutexにはより厳密で狭い使用例があります。n一度に1つのタスクのみがmutexを保持できます。つまり、ミューテックスの使用回数は常に1です。

  1. mutexをロックした人は、ロックを解除する必要があります。つまり、あるコンテキストでmutexをロックしてから、別のコンテキストでロックを解除することはできません。つまり、mutexはカーネルとユーザー空間の間のより複雑な同期には適していません。ただし、ほとんどの使用例では、同じコンテキストから完全にロックおよびロック解除します。
  2. 再帰的なロックとロック解除は許可されていません。つまり、同じmutexを再帰的に取得したり、ロック解除されたmutexをロック解除したりすることはできません。
  3. mutexを保持している間、プロセスは終了できません。
  4. mutexは、mutex_trylock()を使用しても、割り込みハンドラーまたは下半分で取得できません。
  5. mutexは公式APIを介してのみ管理できます。このセクションで説明するメソッドを介して初期化する必要があり、コピー、手動で初期化、または再初期化することはできません。

[1] Linuxカーネル開発、第3版Robert Love


1

ここでの答えのほとんどは混乱を招いたと思います。特に、ミューテックスはそれを保持するプロセスによってのみ解放できるが、セマフォはyプロセスによって信号を送ることができると言っているものは混乱していると思います。上記の行は、セマフォに関しては漠然としています。理解するには、セマフォには2種類あり、1つはカウンティングセマフォと呼ばれ、もう1つはバイナリセマフォと呼ばれます。セマフォのカウントでは、n個のリソースへのアクセスを処理します。nは使用前に定義できます。各セマフォには、使用中のリソース数のカウントを保持するカウント変数があり、最初はnに設定されています。リソースを使用したい各プロセスは、セマフォに対してwait()操作を実行します(これにより、カウントが減少します)。プロセスがリソースを解放するとき、それはrelease()操作(カウントをインクリメント)を実行します。カウントが0になると、すべてのリソースが使用されています。その後、プロセスはカウントが0を超えるまで待機します。これが、リソースを保持するプロセスのみがカウントを増やすことができるキャッチです。他のプロセスはカウントを増やすことができません。リソースを保持するプロセスだけがカウントを増やすことができます。セマフォを再度待機してチェックを行い、利用可能なリソースを見つけると、カウントを再び減らします。したがって、バイナリセマフォに関しては、セマフォを保持するプロセスだけがカウントを増やすことができ、セマフォの使用を停止してカウントを増やし、他のプロセスがセマフォにアクセスする機会を得るまで、カウントはゼロのままです。ここで、リソースを保持するプロセスのみがカウントを増やすことができるキャッチがあります。他のプロセスはカウントを増やすことができません再びカウントを減らします。したがって、バイナリセマフォに関しては、セマフォを保持するプロセスだけがカウントを増やすことができ、セマフォの使用を停止してカウントを増やし、他のプロセスがセマフォにアクセスする機会を得るまで、カウントはゼロのままです。ここで、リソースを保持するプロセスのみがカウントを増やすことができるキャッチがあります。他のプロセスはカウントを増やすことができません再びカウントを減らします。したがって、バイナリセマフォに関しては、セマフォを保持するプロセスだけがカウントを増やすことができ、セマフォの使用を停止してカウントを増やし、他のプロセスがセマフォにアクセスする機会を得るまで、カウントはゼロのままです。

バイナリセマフォとミューテックスの主な違いは、セマフォはシグナルメカニズムであり、ミューテックスはロックメカニズムですが、バイナリセマフォはミューテックスのように機能して混乱を招くように見えますが、どちらも異なる種類の作業に適した異なる概念です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.