C ++スレッドセーフマップ
-
03-07-2019 - |
質問
std :: map
をラップしてスレッドセーフにする実装を見つけることができる場所を誰か知っていますか?スレッドセーフとは、一度に1スレッドずつ、マップへのシリアルアクセスのみを提供することを意味します。最適には、このマップは標準ライブラリおよび/またはブースト構造のみを使用する必要があります。
解決
指定した基準を満たしていませんが、 TBB コンテナを見ることができます。いわゆる concurrent_hash_map
があり、複数のスレッドがマップ内のデータに同時にアクセスできます。いくつかの詳細がありますが、すべてがきちんと文書化されており、「同時コンテナ」の概念を知ることができます。ニーズによっては、これはまったく不適切かもしれません...
他のヒント
コレクションクラスがスレッドセーフを提供することは、コレクションクラスがどのように使用されているかを知ることができないため、一般的には良い考えではありません。コレクションを使用するより高いレベルの構成体に独自のロックメカニズムを実装することにより、サービスが向上します。
ブーストshared_mutexは、制約を考慮して標準マップをラップするための最良のマルチリーダー/シングルライターアプローチを提供します。 「構築済み」がわからないタスクは一般に簡単なので、これら2つを結合する実装。
これは、実装するアプリケーション次第です。 「スレッドセーフ」 mapはマップに対して個別の呼び出しをスレッドセーフにしますが、多くの操作はスレッドセーフ across 呼び出しを行う必要があります。マップを使用するアプリケーションは、ミューテックスをマップに関連付け、そのミューテックスを使用してマップへのアクセスを調整する必要があります。
スレッドセーフコンテナを作成しようとするのはJavaの誤りであり、C ++の誤りです。
このライブラリを試してください
http://www.codeproject.com/KB/threads/lwsync.aspx
最新のC ++ポリシーベースのアプローチで実装されています。
ここでは、「ベクトル」の場合のアイデアを示すために、リンクからいくつか切り取りました
typedef lwsync::critical_resource<std::vector<int> > sync_vector_t;
sync_vector_t vec;
// some thread:
{
// Critical resource can be naturally used with STL containers.
sync_vector_t::const_accessor vec_access = vec.const_access();
for(std::vector<int>::const_iterator where = vec_access->begin();
where != vec_access->end();
++where;
)
std::cout << *where << std::endl;
}
sync_vector_t::accessor some_vector_action()
{
sync_vector_t::accessor vec_access = vec.access();
vec_access->push_back(10);
return vec_access;
// Access is escalated from within a some_vector_action() scope
// So that one can make some other action with vector before it becomes
// unlocked.
}
{
sync_vector_t::accessor vec_access = some_vector_action();
vec_access->push_back(20);
// Elements 10 and 20 will be placed in vector sequentially.
// Any other action with vector cannot be processed between those two
// push_back's.
}
これを思いつきました(3つ以上の引数を取るように改善できるはずです):
template<class T1, class T2>
class combine : public T1, public T2
{
public:
/// We always need a virtual destructor.
virtual ~combine() { }
};
これにより、次のことが可能になります。
// Combine an std::mutex and std::map<std::string, std::string> into
// a single instance.
combine<std::mutex, std::map<std::string, std::string>> lockableMap;
// Lock the map within scope to modify the map in a thread-safe way.
{
// Lock the map.
std::lock_guard<std::mutex> locked(lockableMap);
// Modify the map.
lockableMap["Person 1"] = "Jack";
lockableMap["Person 2"] = "Jill";
}
std :: recursive_mutexとstd :: setを使用したい場合、それも機能します。
ここ(私による-恥知らずのプラグ)には、オブジェクト( STL
コンテナを含む)をラップして効率的(ゼロコスト)のスレッドセーフアクセスを実現する提案があります。
https://github.com/isocpp/CppCoreGuidelines/issues/924
基本的な考え方は非常に単純です。読み取り/書き込みロックを強制するために使用されるラッパークラスがいくつかあり、同時に、ラップされたオブジェクトのconst(読み取り専用)または非const(読み取り/書き込み)ビューのいずれかを提示します。
アイデアは、スレッド間で共有されているリソースに不適切にアクセスすることをコンパイル時に不可能にすることです。
実装コードは次の場所にあります:
https://github.com/galik/GSL / blob / lockable-objects / include / gsl / gsl_lockable