web-dev-qa-db-ja.com

C ++でmutexを介してセマフォを使用するのはどのような場合ですか?

私がマルチスレッド化について読んだリソース全体を通して、セマフォと比較して、mutexがより頻繁に使用され、議論されています。私の質問は、いつミューテックスでセマフォを使用するのですか? Boostスレッドにセマフォが表示されません。それは最近セマフォがあまり使われなくなったことを意味しますか?

私が理解している限り、セマフォを使用すると、リソースを複数のスレッドで共有できます。これは、それらのスレッドがリソースを読み取るだけで書き込みを行っていない場合にのみ可能です。これは正しいです?

36
jasonline

Boost.Threadにはミューテックスと条件変数があります。機能的には純粋にセマフォは冗長です[*]。そのため、セマフォが省略されているのかどうかはわかりません。

セマフォはより基本的なプリミティブで、シンプルであり、高速化のために実装されている可能性がありますが、優先順位の逆転はありません。投稿の数が適切な方法で待機の数と「一致」するようにクライアントコードを要求するため、条件変数よりも間違いなく使用が困難です。条件変数を使用すると、誰も実際に条件をチェックせずにdoes何もしないため、偽の投稿を容認するのは簡単です。

読み取りリソースと書き込みリソースはレッドニシンIMOであり、ミューテックスとセマフォの違いとは何の関係もありません。カウントセマフォを使用する場合、複数のスレッドが同じリソースに同時にアクセスしている状況が発生する可能性があります。その場合、おそらく読み取り専用アクセスでなければなりません。そのような状況では、shared_mutex代わりにBoost.Threadから。ただし、セマフォはミューテックスのようにリソースを保護するためのものではなく、スレッド間で信号を送信するためのものです。 seを使用して、リソースへのアクセスを制御することができます。

これは、セマフォのすべての使用が読み取り専用リソースに関連している必要があるという意味ではありません。たとえば、バイナリセマフォを使用して、読み取り/書き込みリソースを保護できます。ただし、mutexを使用すると、スケジューリングの動作が向上することがよくあります。

[*] mutexと条件変数を使用してカウントセマフォを実装する方法の概要を次に示します。もちろん共有セマフォを実装するには、共有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);

したがって、セマフォで実行できることは何でも、ミューテックスと条件変数で実行できます。ただし、実際にセマフォを実装する必要はありません。

4
Steve Jessop

Mutexの一般的な使用例(いつでも1つのスレッドのみがリソースにアクセスできるようにする)は、セマフォの場合の一般的な使用法よりもはるかに一般的です。しかし、セマフォは実際にはより一般的な概念です。ミューテックスは(ほぼ)セマフォの特殊なケースです。

一般的なアプリケーションは次のとおりです。たとえば、5つを超えるデータベース接続を作成したくない場合。ワーカースレッドがいくつあっても、これらの5つの接続を共有する必要があります。または、Nコアマシンで実行する場合、特定のCPU /メモリを集中的に使用するタスクが同時にNを超えるスレッドで実行されないようにする必要がある場合があります(コンテキストの切り替えによりスループットが低下するだけなので)キャッシュスラッシング効果)。並列CPU /メモリ集中タスクの数をN-1に制限して、システムの他の部分が不足しないようにすることもできます。または、特定のタスクが大量のメモリを必要とする場合、そのタスクのN個を超えるインスタンスを同時に実行するとページングが発生することを想像してください。ここでセマフォを使用して、この特定のタスクのN個を超えるインスタンスが同時に実行されないようにすることができます。

編集/ PS:「これは、これらのスレッドがリソースを読み取るだけで書き込みを行わない場合にのみ可能です。これは正しいですか?」そしてあなたのコメント、それはあなたがリソースを変数またはストリームとして考えているかのように思えます。それは読み取りまたは書き込みが可能で、一度に1つのスレッドによってのみ書き込みが可能です。しないでください。これは、この文脈では誤解を招くものです。

「水」のような資源について考えてください。水を使って皿を洗うことができます。同時に水で皿を洗うことができます。両方に十分な水があるので、そのために同期を行う必要はありません。 同じ水を使用する必要はありません。 (そして、水を「読み取る」または「書き込む」ことはできません。)しかし、水の総量有限です。したがって、any人数で同時に皿を洗うことはできません。この種の同期はセマフォで行われます。通常、水ではなく、メモリ、ディスク容量、IOスループットまたはCPUコアなどの他の有限リソースを使用します。

25
Niki

Mutexとセマフォの違いの本質は、所有権の概念に関係しています。 mutexが取得されると、そのスレッドはmutexを所有していると見なし、同じスレッドは後でmutexを解放してリソースを解放する必要があります。

セマフォの場合、セマフォをリソースを消費していると考えますが、実際にはその所有権を取得していません。これは通常、セマフォがスレッドによって所有されているのではなく「空」であると呼ばれます。セマフォの特徴は、別のスレッドがセマフォを「一杯」にして「フル」状態に戻すことができることです。

したがって、通常、mutexはリソースの同時実行性保護(つまり、MUTual EXlusion)に使用され、セマフォはスレッド間のシグナリング(船舶間のセマフォフラグのような)に使用されます。ミューテックス自体は実際にはシグナリングに使用できませんが、セマフォは使用できます。したがって、どちらを選択するかは、実行しようとしていることに依存します。

再帰的mutexと非再帰的mutexの違いをカバーする関連トピックの詳細については、別の ここに私の回答の1つ を参照してください。

11
Tall Jeff

複数のスレッド(プロセス間またはプロセス内)で共有されている限られた数のリソースへのアクセスを制御します。

このアプリケーションでは、非常に重いリソースがあり、M個のワーカースレッドのそれぞれにリソースを割り当てたくありませんでした。ワーカースレッドはジョブのごく一部にリソースを必要としたため、同時に2つ以上のリソースを使用することはほとんどありませんでした。

したがって、N個のリソースを割り当て、それらをNに初期化されたセマフォの背後に配置しました。N個を超えるスレッドがリソースを使用しようとすると、リソースが使用可能になるまでブロックされます。

9

[〜#〜]本当に[〜#〜]セマフォに関する重要な情報を無視せずに質問に答える簡単な方法はないように思います。人々は セマフォに関する多くの本 を書いているので、1つまたは2つのパラグラフの答えはすべて不快です。人気の本は セマフォの小さな本 ...大きな本が嫌いな人向けです:)。

ここにまともな 長い記事 があり、セマフォの使用方法とセマフォの使用方法の詳細について説明します。

更新:
ダンは私の例のいくつかの間違いを指摘しました、私は私よりはるかに良い説明を提供する参照にそれを残します:).

以下は、セマフォを使用する正しい方法を示すリファレンスです。
1。IBM記事
2。シカゴ大学クラス講義
。最初に投稿したNetrinoの記事
4。「販売チケット」用紙+コード

3
Kiril

この記事 から:

ミューテックスを使用すると、プロセス間同期を実行できます。ミューテックスを名前でインスタンス化すると(上記のコードのように)、ミューテックスはシステム全体になります。これは、多くの異なるアプリケーション間で同じライブラリを共有していて、共有できないリソースにアクセスしているコードの重要なセクションへのアクセスをブロックする必要がある場合に非常に役立ちます。

最後に、Semaphoreクラス。本当にCPUを集中的に使用するメソッドがあり、アクセスの制御に必要なリソースを使用しているとします(Mutexes :)を使用)。また、メソッドへの最大5回の呼び出しは、マシンを無応答にすることなく処理できるすべてのことであると判断しました。ここでの最良の解決策は、リソースへの特定の数のスレッドのアクセスを制限できるSemaphoreクラスを利用することです。

1
Kane

私が理解している限り、セマフォは最近のIPC関連の用語です。それでも、多くのプロセスが変更できる保護変数を意味しますが、プロセスとこの機能はOSでサポートされています。

通常、変数は必要なく、単純なミューテックスですべての要件をカバーします。それでも変数が必要な場合は、おそらくそれを自分でコーディングします-「変数+ミューテックス」で、より詳細に制御できます。

再開:通常、単純化と制御のためにミューテックスを使用するため、マルチスレッドでセマフォを使用しません。また、IPCにはセマフォを使用します。これは、OSがサポートし、プロセス同期メカニズムの正式名であるためです。

0
seas

セマフォは元々、プロセス間の同期のために考案されました。 Windowsは、セマフォのようなWaitForMultipleObjectsを使用します。 Linuxの世界では、最初のpthread実装では、プロセス間でミューテックスを共有できませんでした。今はそうです。スレッドがCPUのスケジューリングの単位になった後の最近では、軽量のミューテックスとともにアトミックインクリメント(Windowsではインターロックされたインクリメント)を壊すという概念が最も実用的な実装です。増分とロックが一緒になっている場合(セマフォ)、ロックの取得/解放に時間がかかりすぎて、パフォーマンスと同期構造を改善するために、今日のように2つのユニット関数を分割できません。

0
MRN