38

同時に書き込まれるオブジェクトの数が多いが、潜在的に変化する可能性があります。そのアクセスをミューテックスで保護したい。そのために、私は を使用すると思っていましたが、コピーまたは移動コンストラクターがないstd::vector<std::mutex>ため、これは機能しません。std::mutexstd::vector::resize()

この難問に対する推奨される解決策は何ですか?

edit : すべての C++ ランダム アクセス コンテナーは、サイズ変更のためにコピーまたは移動コンストラクターを必要としますか? std::deque は役に立ちますか?

再編集

まず、あなたのすべての考えに感謝します。ミュートを回避したり、オブジェクトに移動したりするソリューションには興味がありません(詳細/理由の説明は控えます)。そのため、ミューテックスの数を調整したいという問題 (ミューテックスがロックされていないときに調整が行われることが保証されている場合) を考えると、いくつかの解決策があるようです。

1固定数のミュートを使用し、ハッシュ関数を使用してオブジェクトからミュートにマップできます(キャプテンオブリバスの回答のように)。これにより衝突が発生しますが、mutice の数がスレッドの数よりもはるかに多くても、オブジェクトの数よりも少ない場合、衝突の数は少なくなるはずです。

2ラッパークラスを定義できます(ComicSansMSの回答のように)、たとえば

struct mutex_wrapper : std::mutex
{
  mutex_wrapper() = default;
  mutex_wrapper(mutex_wrapper const&) noexcept : std::mutex() {}
  bool operator==(mutex_wrapper const&other) noexcept { return this==&other; }
};

を使用しstd::vector<mutex_wrapper>ます。

3std::unique_ptr<std::mutex>個々のミューテックスを管理するために使用できます(Matthias の回答のように)。このアプローチの問題は、各ミューテックスがヒープ上で個別に割り当てられ、割り当て解除されることです。したがって、私は好む

4 std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );

特定の数n_mutexのミュートが最初に割り当てられたとき。この数が後で不十分であることが判明した場合、私は単純に

if(need_mutex > n_mutex) {
  mutices.reset( new std::mutex[need_mutex] );
  n_mutex = need_mutex;
}

では、これらの (1,2,4) のどれを使用すればよいでしょうか?

4

7 に答える 7

19

vector値が大きくなるにつれて連続した値の配列を維持するために、値が移動可能である必要があります。ミューテックスを含むベクターを作成することはできましたが、サイズ変更が必要になるようなことは何もできませんでした。

他のコンテナにはその要件がありません。構築中、またはまたはを使用してミューテックスを適切に構築する限り、または のいずれdequeかが機能するはずです。やなどの機能は動作しません。[forward_]listemplace()resize()insert()push_back()

または、追加レベルの間接化と store を追加することもできますunique_ptr。しかし、別の回答でのあなたのコメントは、動的割り当ての追加コストが許容できないと考えていることを示しています。

于 2013-05-09T16:05:09.580 に答える
17

std::unique_ptr<std::mutex>の代わりに使用できますstd::mutexunique_ptr可動します。

于 2013-05-09T15:45:32.477 に答える
7

固定ミューテックス プールを使用することをお勧めします。の固定配列を保持std::mutexし、ハッシュ テーブルの場合と同様に、オブジェクトのアドレスに基づいてロックする配列を選択します。

std::array<std::mutex, 32> mutexes;

std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()];

m.lock();

関数はhashof、ポインター値を数ビットシフトする単純なものである可能性があります。この方法では、mutex を 1 回初期化するだけで済み、ベクターのサイズ変更のコピーを回避できます。

于 2013-05-09T16:30:55.810 に答える
3

効率がそのような問題である場合、非常に頻繁に変更される非常に小さなデータ構造しかないと思います。特に、mutex を使用する代わりに、Atomic Compare And Swap (およびその他のアトミック操作) を使用することをお勧めします。std::atomic_compare_exchange_strong

于 2013-05-10T10:47:35.490 に答える