0

イベントが発生したときにマルチスレッドを使用してメンバー関数を呼び出すライブラリを使用しています。ライブラリ内の各「ハンドラ」には、 function を呼び出すことができるスレッドがありますMyClass::Process(const Signal& signal)。MyClass には、 というCatalogクラスへの参照がありcatます。

内部にProcessは次のコードがあります。

Stats stats;//simple container struct to hold values

std:string id(signal.signalId());
//set values of stats here based on the values in signal

cat->onSignalUpdate(id, stats);

ライブラリのドキュメントから:

Handler の単一インスタンスの境界では、2 つのユーザー コールバックを同時に呼び出すことはできません。ただし、異なるチャネルの Handler の異なるインスタンスは相互にリンクされていないため、異なる Handler インスタンスからの呼び出しが並行して発生する可能性があります。

カタログにはメンバーがいますstd::map<std::string, Stats> signal_map

の中にCatalog::onSignalUpdate(const std::string& id, const Stats& stats)

std::map<std::string, Stats>::iterator it(signal_map.find(id));
if(it != signal_map.end())
{
    it->second = stats;
}

これは、適切な Id が適切な Stats 構造体にマップされている場合に、ほとんどの場合機能します。ハンドラー A の ID がハンドラー B の ID に属する構造体に割り当てられている場合、不適切なマッチングが発生することがあります。関数が並行して呼び出されているように見えます。スレッド化では、並列処理中に関数呼び出しが重複するという印象を受けました。そうではありませんか、それともスレッドで参照によって値を渡すことに問題がありますか?

4

1 に答える 1

2

複数のスレッドが同時に をstd::map変更することに対する何らかの保護がなければ、複数のスレッドから を更新することはできません。mapそれらの線に沿ってミューテックスまたは何かが必要です。特に、idが「新しい」場合、マップ内の基礎となるデータ構造 (通常は「RB ツリー」) が変更されます。これは、複数のスレッドから実行してはなりません。また、ツリーのエントリが「半分更新」されている可能性があるため、変更中にツリーにアクセスして「読み取る」こともできません (たとえば、次の要素が適切に入力されていない要素を指している、またはいくつかのそのような)。

于 2013-10-16T21:36:05.413 に答える