concurrent_hash_map ミューテックス・タイプをカスタマイズ#
注
この機能を有効にするには、TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS マクロを 1 に定義します。
説明#
oneTBB の concurrnent_hash_map クラスは、リーダー/ライター・ミューテックスを使用してスレッドセーフを提供し、挿入、検索、および消去操作のデータ競合を回避します。この機能により、concurrent_hash_map に追加のテンプレート・パラメーターが追加され、リーダー/ライター・ミューテックスのタイプをカスタマイズできるようになります。
API#
ヘッダー#
#include <oneapi/tbb/concurrent_hash_map.h>概要#
namespace oneapi {
namespace tbb {
template <typename Key, typename T,
typename HashCompare = tbb_hash_compare<Key>,
typename Allocator = tbb_allocator<std::pair<const Key, T>>,
typename Mutex = spin_rw_mutex>
class concurrent_hash_map {
using mutex_type = Mutex;
};
} // namespace tbb
} // namespace oneapiタイプの要件#
concurrent_hash_map のテンプレート引数として渡されるミューテックスのタイプは、ReaderWriterMutex の要件を満たしている必要があります。また、次の API も提供する必要があります。
- bool ReaderWriterMutex::scoped_lock::is_writer() const;#
戻り値: scoped_lock オブジェクトがミューテックスをライターとして取得する場合は true、それ以外の場合は false。
scoped_lock オブジェクトがミューテックスを取得しない場合、動作は未定義になります。
oneapi::tbb::spin_rw_mutex、oneapi::tbb::speculative_spin_rw_mutex、oneapi::tbb::queuing_rw_mutex、oneapi::tbb::null_rw_mutex、および oneapi::tbb::rw_mutex は上記の要件を満たしています。
例
以下の例は、ReaderWriterMutex の要件を満たすため std::shared_mutex をラップする方法と、このミューテックスを使用するために concurrent_hash_map をカスタマイズする方法を示しています。
#define TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS 1
#include "oneapi/tbb/concurrent_hash_map.h"
#include <shared_mutex>
class SharedMutexWrapper {
public:
// ReaderWriterMutex の要件
static constexpr bool is_rw_mutex = true;
static constexpr bool is_recursive_mutex = false;
static constexpr bool is_fair_mutex = false;
class scoped_lock {
public:
scoped_lock() : my_mutex_ptr(nullptr), my_writer_flag(false) {}
scoped_lock(SharedMutexWrapper& mutex, bool write = true)
: my_mutex_ptr(&mutex), my_writer_flag(write)
{
if (my_writer_flag) {
my_mutex_ptr->my_mutex.lock();
} else {
my_mutex_ptr->my_mutex.lock_shared();
}
}
~scoped_lock() {
if (my_mutex_ptr) release();
}
void acquire(SharedMutexWrapper& mutex, bool write = true) {
if (my_mutex_ptr) release();
my_mutex_ptr = &mutex;
my_writer_flag = write;
if (my_writer_flag) {
my_mutex_ptr->my_mutex.lock();
} else {
my_mutex_ptr->my_mutex.lock_shared();
}
}
bool try_acquire(SharedMutexWrapper& mutex, bool write = true) {
if (my_mutex_ptr) release();
my_mutex_ptr = &mutex;
bool result = false;
if (my_writer_flag) {
result = my_mutex_ptr->my_mutex.try_lock();
} else {
result = my_mutex_ptr->my_mutex.try_lock_shared();
}
if (result) my_writer_flag = write;
return result;
}
void release() {
if (my_writer_flag) {
my_mutex_ptr->my_mutex.unlock();
} else {
my_mutex_ptr->my_mutex.unlock_shared();
}
}
bool upgrade_to_writer() {
// std::shared_mutex にはアップグレード/ダウングレードのセマンティクスがありません
if (my_writer_flag) return true; // すでにライター
my_mutex_ptr->my_mutex.unlock_shared();
my_mutex_ptr->my_mutex.lock();
return false; // ロックが再取得されました
}
bool downgrade_to_reader() {
if (!my_writer_flag) return true; // すでにリーダー
my_mutex_ptr->my_mutex.unlock();
my_mutex_ptr->my_mutex.lock_shared();
return false;
}
bool is_writer() const {
return my_writer_flag;
}
private: SharedMutexWrapper* my_mutex_ptr;
bool my_writer_flag;
};
private:
std::shared_mutex my_mutex;
}; // SharedMutexWrapper 構造体
int main() {
using map_type = oneapi::tbb::concurrent_hash_map<int, int,
oneapi::tbb::tbb_hash_compare<int>,
oneapi::tbb::tbb_allocator<std::pair<const int, int>>,
SharedMutexWrapper>;
map_type map; // このオブジェクトは、挿入/検索/消去操作のスレッドセーフのため SharedMutexWrapper を使用します
}