concurrent_hash_map ミューテックス・タイプのカスタマイズ

concurrent_hash_map ミューテックス・タイプをカスタマイズ#

この機能を有効にするには、TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS マクロを 1 に定義します。

説明#

oneTBB の concurrnent_hash_map クラスは、リーダー/ライター・ミューテックスを使用してスレッドセーフを提供し、挿入、検索、および消去操作のデータ競合を回避します。この機能により、concurrent_hash_map に追加のテンプレート・パラメーターが追加され、リーダー/ライター・ミューテックスのタイプをカスタマイズできるようになります。

API#

概要#

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_mutexoneapi::tbb::speculative_spin_rw_mutexoneapi::tbb::queuing_rw_mutexoneapi::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 を使用します 
}