9

私はスレッドに少し慣れていないので、C++ 11 でスレッドがどのように機能するかを理解しようとしています。私のクラスの教授は、ミューテックスの使用方法を示すために次のサンプル コードを提供してくれました。

#include <list> 
#include <mutex> 
#include <algorithm>

std::list<int> some_list; // A data structure accessed by multiple threads
std::mutex some_mutex; // This lock will prevent concurrent access to the shared data structure

void
add_to_list(int new_value) {
    std::lock_guard<std::mutex> guard(some_mutex); // Since I am going to access the shared data struct, acquire the lock
    some_list.push_back(new_value); // Now it is safe to use some_list. RAII automatically releases lock at end of function }
}

bool
list_contains(int value_to_find) {
    std::lock_guard<std::mutex> guard(some_mutex); // Must get lock every time I access some_list return
    std::find (some_list.begin(),some_list.end(),value_to_find) != some_list.end();
}

コードはある程度自明だと思いますが、具体的な質問がいくつかありました。

  1. ミューテックスをリストに具体的に関連付ける必要はありませんか?
  2. そうでない場合、mutex が使用されるたびに、mutex が破棄されるまですべてのスレッドが停止するということですか? それとも、スレッドのサブセットにすぎませんか。おそらくいくつかのスレッドプール内のスレッドか、そうでなければ互いに関連付けられていますか?
  3. いずれにせよ、データ構造にアクセスしようとしているスレッドだけを停止する方がよいのではないでしょうか? それ以外の場合は、データ競合などについて心配する必要がないからです。
  4. 最後に、ミューテックスとロックの違いは何ですか? ミューテックスは単なる RAII ロックですか? それとも、ガード経由で RAII が発生していますか?
4

4 に答える 4

6
  1. ミューテックスはリストに関連付けられていますが、この関連付けは完全に手動です。コンパイラとランタイム ライブラリは、この 2 つが関連付けられていることを知りません。関連付けはドキュメントと頭の中に完全に存在し、リストにアクセスするスレッドが最初にミューテックスをロック/取得することを保証する責任があります。

  2. ミューテックスが使用されるたびに、ミューテックスをロック/取得するスレッドは、他のスレッドがミューテックスを所有しなくなるまで停止します (この用語は実際にはblock です)。ミューテックスを使用していないスレッドは影響を受けません。

  3. リストにアクセスするスレッドのみがミューテックスをロック/取得することを保証する責任があり、リストにアクセスするすべてのスレッドがミューテックスをロック/取得することを保証する責任もあります。繰り返しになりますが、これらのスレッドのみがミューテックスの待機をブロックできます。

  4. 同じオブジェクトが、"mutex"、"lock"、または "critical section" など、さまざまな名前で呼ばれています。ガードは RAII を使用してミューテックスをロック/取得します。

于 2013-02-02T19:30:07.197 に答える
3

ミューテックスをリストに具体的に関連付ける必要はありませんか?

いいえ、または少なくとも明示的にではなく、これは一般的に宣言的な方法では不可能です。コードは、そのミューテックスによって保護されているオブジェクトにアクセスする必要があるたびに、適切なミューテックスを取得(試行)し、状態の読み取りまたは変更が完了した後に解放する必要があります。どのミューテックスがどのオブジェクトを保護するかについての知識は、プログラマーの頭の中だけにあります(もちろん、プログラムのドキュメントにもあります)。

そうでない場合は、ミューテックスが使用されるたびに、ミューテックスが破棄されるまですべてのスレッドが停止することを意味しますか?それとも、スレッドのサブセットにすぎません。おそらく、いくつかのスレッドプール内のスレッド、または他の方法で相互に関連付けられているスレッドですか?

つまり、特定のオブジェクトに対してアトミックシーケンスの操作を実行するすべてのスレッドは、最初にそのオブジェクトを保護するミューテックスを取得して、同じリソースを競合する他のスレッドとアクセスを同期する必要があります。ミューテックスは、1つのスレッドのみがミューテックスを所有できることを保証し、このスレッドがミューテックスを解放する(「破棄」しない)まで、他のすべてのスレッドはミューテックスの取得を待機します。

どちらの場合でも、データ構造にアクセスしようとしているスレッドのみを停止する方がよいのではないでしょうか。それ以外の場合は、データの競合などについて心配する必要はありません。

はい、確かに。特定のオブジェクトへの排他的アクセスを必要とするスレッド(およびそれらのスレッドのみ)を強制して、そのオブジェクトを保護するミューテックスを取得することにより、他のスレッドを強制的に停止することはありません。

最後に、ミューテックスとロックの違いは何ですか?ミューテックスは単なるRAIIロックですか?それとも、RAIIは警備員を介して起こっていますか?

ミューテックスは、他のスレッドがその操作を妨害することを心配することなく、クライアントがそのミューテックスによって保護されたオブジェクトに対して特定の操作を実行するために取得できる(しようとする)同期オブジェクトです(他のスレッドも取得しようとするプロトコルを尊重する限り)もちろん、オブジェクトにアクセスする前のミューテックス)。

ロックは通常、ミューテックスのロックをカプセル化するRAIIラッパーオブジェクトとして理解され、そのデストラクタは呼び出されるとミューテックスのロックを自動的に解除します。したがって、ロックがスコープ外になると(関数から戻ったため、または例外がスローされたためなど)、取得したミューテックスは自動的に解放されます。

于 2013-02-02T19:35:43.983 に答える
3

ミューテックスをリストに具体的に関連付ける必要はありませんか?

いいえ、ありません。このコンテキストでは、ミューテックスはリスト自体ではなく、単にコードのブロックを保護しています。some_list.push_back()とは同じミューテックスによって保護されたコード ブロックで実行されるためstd::find、1 つのスレッドがブロックを終了するまで、個別のスレッドが保護されたブロック内で一緒に伝播することはありません。

そうでない場合、mutex が使用されるたびに、mutex が破棄されるまですべてのスレッドが停止するということですか? それとも、スレッドのサブセットにすぎませんか。おそらくいくつかのスレッドプール内のスレッドか、そうでなければ互いに関連付けられていますか?

いいえ - ミューテックスによって保護されたブロックに入ろうとするすべてのスレッドは、ミューテックスがロック解除lock_guardされるまで中断されます (ミューテックスを保持しているオブジェクトを破棄することによって発生する可能性があります)。

いずれにせよ、データ構造にアクセスしようとしているスレッドだけを停止する方がよいのではないでしょうか? それ以外の場合は、データ競合などについて心配する必要がないからです。

前述したように、保護されたブロックにアクセスしようとしているスレッドのみが中断される可能性があるため、すべてのスレッドをブロックする必要はありません。

最後に、ミューテックスとロックの違いは何ですか? ミューテックスは単なる RAII ロックですか? それとも、ガード経由で RAII が発生していますか?

いいえ、ミューテックスは単に同期プリミティブであり、異なるシステムでは異なる方法で実装されていますが、C++ はそれに統一されたインターフェイスを提供しています。ミューテックス自体はlock、 、try_lockの3 つの操作しか認識しないunlockため、さまざまなラッパーが存在します。RAII を提供するそのうちの 1 つがstd::lock_guard.

于 2013-02-02T19:36:30.373 に答える
2

ミューテックスをリストに具体的に関連付ける必要はありませんか?

いいえ、手動で行います。

そうでない場合、それはミューテックスが使用されるとき、すべてのスレッドがミューテックスが破壊されるまで停止することを意味しますか?または、スレッドのサブセットのみです。おそらく、スレッドプールのスレッド、または互いに関連付けられているのでしょうか?

ミューテックス = 相互排除。2 つのスレッドがミューテックスをロックしようとすると、そのうちの 1つがそのミューテックスが解放されるまでブロックされます。別のスレッドがロックしているときにミューテックスをロックしようとすると、解放されるまでブロックされます。

いずれにせよ、データ構造にアクセスしようとしているスレッドだけを停止する方がよいのではないでしょうか? それ以外の場合は、データ競合などについて心配する必要がないからです。

はい。同時アクセスに問題がある間は、データ構造を保護しているミューテックスのみをロックする必要があります。たとえば、データ構造を変更する場合。これが、関数が の期間add_to_listだけミューテックス ( ) をロックする理由です。some_mutexsome_list.push_back()

最後に、ミューテックスとロックの違いは何ですか? ミューテックスは単なる RAII ロックですか?

C++ lock_guard は、ミューテックスの RAII ラッパーです。オブジェクトが作成されるとミューテックスはロックされ、オブジェクトが破棄される (範囲外になる) とミューテックスはロック解除されます。

于 2013-02-02T19:28:55.413 に答える