2
Pseudocode:
Function1_vector_copy () {
vectora = vectorb;
}
Function2_vector_search() {
find k in vectora;
}

プログラムはマルチスレッドです。多くのスレッドが を検索する可能性がありますが、ベクトルのコピーは単一のスレッドによってのみ行われますが、時折行われます。問題は何であれ、vector_search は失敗しないはずです。vector_copy は延期できますが、vector_search は延期しないでください。遅延も障害パターンもありません。問題は、 vector_search がまったく失敗しないように、永続的でなければならない共有変数 vectora です。これを達成するための最適な方法は何ですか?

編集 :

別の質問に対する回答の使用

boost::shared_mutex _access;

Function1_vector_copy() {

  // get upgradable access
  boost::upgrade_lock lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock uniqueLock(lock);
  // now we have exclusive access

  vectora.swap(vectorb);
}

Function2_vector_search() {

  // get shared access
  boost::shared_lock lock(_access);

  // now we have shared access

  find k in vectora ;

}

アップグレード可能な所有権を持つスレッドがアップグレードを試み、他のスレッドが所有権を共有している場合、その試みは失敗し、排他的な所有権を取得できるまでスレッドはブロックされます。 --boost-ドキュメンテーション

秘訣は、ベクターのコピーが非同期で行われ、排他的な所有権が取得された後に行われることです。したがって、ベクターコピーは最終的に発生しますが延期され、実際にベクターコピーも失敗しない操作ですが遅延します。これは私にとっては問題ありません。何らかの形で同期のためにロックがかかり、少なくとも 1 ミリ秒はブロックされます。しかし、このスワップを使用する利点は、時間の短縮につながり、無視できるようになります。

4

2 に答える 2

2

mcmccのアイデアはそれほど遠くはなかったと思いますが、代わりにベクトルコピーを実行する汎用のstd :: swap()を使用すると、std :: vector :: swap()を使用できるはずです。機能的には、ベクトルのスワップ関数はジェネリック関数と同じように機能しますが、ポインター/サイズ変数をほとんど交換せず、実際には要素のコピーを行わないため、はるかに高速です。したがって、ロックはいくつかの組み立て手順でのみ使用できます。

それでも長すぎる場合(その時点で、設計を確認することをお勧めします)、別の方法は、互いに置き換えられないベクトルの循環リストを作成することです。代わりに、「アクティブな」ベクトルを参照する別のポインターがあります。そのコレクションを変更する必要がある場合は、円内の次のベクトルを初期化し、初期化が完了したら、ポインターを更新します。このソリューションでは、ロックはまったくありません。読者が1つのベクトルを使用している瞬間と、別のベクトルを使用している瞬間。

2番目のソリューションの欠点は、間違いなくより多くのメモリが必要になり、少し予測できないことです。「アクティブな」ベクトルポインターを揮発性と宣言すると、ポインター値が読み取られるたびにキャッシュが同期されるように強制されます。そうでない場合、複数のCPUコアがメインの異なるスナップショットを参照している可能性がある非決定的な要素があります。メモリー。また、同期を行わずに、他のスレッドが吹き飛ばされようとしているベクトルで実行されるようにするにはどうすればよいですか?そして、何らかの同期を行うと、RWロックに戻ります。

私はあなたが仕事に2番目の選択肢を得ることができると思いますが、比較的安定して微調整することで...おそらく。私の最初の本能は、RWロックとvector :: swap()を使用することです。

更新:実際、私は仕様を読み直しただけで、STLはstd::vectorを含むコンテナー専用のグローバルstd::swapを専門にしているように見えます。したがって、グローバル関数を呼び出す場合でも、複雑さはO(1)です。mcmccの答えは機能します。

したがって、この推測を休ませて、コードを少し記述し、デバッガーを使用してステップスルーしました。これが私のアプリケーションコードです:

std::vector< int >      a, b;

for( int i = 0; i < 10; i++ )
{
    a.push_back( i );
    b.push_back( i * 10 );
}

std::swap( a, b );

std::swapのグローバルな汎用バージョンへの呼び出しの内容は次のとおりです。

template<class _Ty,
class _Alloc> inline
void swap(vector<_Ty, _Alloc>& _Left, vector<_Ty, _Alloc>& _Right)
{   // swap _Left and _Right vectors
_Left.swap(_Right);
}

ご覧のとおり、汎用モードでコピーコンストラクターを実行する汎用std :: swapテンプレート関数は、ベクター専用になっています。そして内部的には、すべての作業をstd :: vector :: swap()に委任するだけです。これは、私たちが確立したように、より高速なバリアントです。

于 2012-01-31T07:36:56.620 に答える