1.. _custom_mutex_chmap: 2 3The customizing mutex type for ``concurrent_hash_map`` 4====================================================== 5 6.. note:: 7 To enable this feature, define the ``TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS`` macro to 1. 8 9.. contents:: 10 :local: 11 :depth: 1 12 13Description 14*********** 15 16oneTBB ``concurrnent_hash_map`` class uses reader-writer mutex 17to provide thread safety and avoid data races for insert, lookup, and erasure operations. This feature adds an extra template parameter 18for ``concurrent_hash_map`` that allows to customize the type of the reader-writer mutex. 19 20API 21*** 22 23Header 24------ 25 26.. code:: cpp 27 28 #include <oneapi/tbb/concurrent_hash_map.h> 29 30Synopsis 31-------- 32 33.. code:: cpp 34 35 namespace oneapi { 36 namespace tbb { 37 38 template <typename Key, typename T, 39 typename HashCompare = tbb_hash_compare<Key>, 40 typename Allocator = tbb_allocator<std::pair<const Key, T>>, 41 typename Mutex = spin_rw_mutex> 42 class concurrent_hash_map { 43 using mutex_type = Mutex; 44 }; 45 46 } // namespace tbb 47 } // namespace oneapi 48 49Type requirements 50----------------- 51 52The type of the mutex passed as a template argument for ``concurrent_hash_map`` should 53meet the requirements of `ReaderWriterMutex <https://spec.oneapi.com/versions/latest/elements/oneTBB/source/named_requirements/mutexes/rw_mutex.html>`_. 54It should also provide the following API: 55 56.. cpp:function:: bool ReaderWriterMutex::scoped_lock::is_writer() const; 57 58**Returns**: ``true`` if the ``scoped_lock`` object acquires the mutex as a writer, ``false`` otherwise. 59 60The behavior is undefined if the ``scoped_lock`` object does not acquire the mutex. 61 62``oneapi::tbb::spin_rw_mutex``, ``oneapi::tbb::speculative_spin_rw_mutex``, ``oneapi::tbb::queuing_rw_mutex``, ``oneapi::tbb::null_rw_mutex``, 63and ``oneapi::tbb::rw_mutex`` meet the requirements above. 64 65.. rubric:: Example 66 67The example below demonstrates how to wrap ``std::shared_mutex`` (C++17) to meet the requirements 68of `ReaderWriterMutex` and how to customize ``concurrent_hash_map`` to use this mutex. 69 70.. code:: cpp 71 72 #define TBB_PREVIEW_CONCURRENT_HASH_MAP_EXTENSIONS 1 73 #include "oneapi/tbb/concurrent_hash_map.h" 74 #include <shared_mutex> 75 76 class SharedMutexWrapper { 77 public: 78 // ReaderWriterMutex requirements 79 80 static constexpr bool is_rw_mutex = true; 81 static constexpr bool is_recursive_mutex = false; 82 static constexpr bool is_fair_mutex = false; 83 84 class scoped_lock { 85 public: 86 scoped_lock() : my_mutex_ptr(nullptr), my_writer_flag(false) {} 87 scoped_lock(SharedMutexWrapper& mutex, bool write = true) 88 : my_mutex_ptr(&mutex), my_writer_flag(write) 89 { 90 if (my_writer_flag) { 91 my_mutex_ptr->my_mutex.lock(); 92 } else { 93 my_mutex_ptr->my_mutex.lock_shared(); 94 } 95 } 96 97 ~scoped_lock() { 98 if (my_mutex_ptr) release(); 99 } 100 101 void acquire(SharedMutexWrapper& mutex, bool write = true) { 102 if (my_mutex_ptr) release(); 103 104 my_mutex_ptr = &mutex; 105 my_writer_flag = write; 106 107 if (my_writer_flag) { 108 my_mutex_ptr->my_mutex.lock(); 109 } else { 110 my_mutex_ptr->my_mutex.lock_shared(); 111 } 112 } 113 114 void release() { 115 if (my_writer_flag) { 116 my_mutex_ptr->my_mutex.unlock(); 117 } else { 118 my_mutex_ptr->my_mutex.unlock_shared(); 119 } 120 } 121 122 bool upgrade_to_writer() { 123 // std::shared_mutex does not have the upgrade/downgrade parallel_for_each_semantics 124 if (my_writer_flag) return true; // Already a writer 125 126 my_mutex_ptr->my_mutex.unlock_shared(); 127 my_mutex_ptr->my_mutex.lock(); 128 return false; // The lock was reacquired 129 } 130 131 bool downgrade_to_reader() { 132 if (!my_writer_flag) return true; // Already a reader 133 134 my_mutex_ptr->my_mutex.unlock(); 135 my_mutex_ptr->my_mutex.lock_shared(); 136 return false; 137 } 138 139 bool is_writer() const { 140 return my_writer_flag; 141 } 142 143 private: 144 SharedMutexWrapper* my_mutex_ptr; 145 bool my_writer_flag; 146 }; 147 private: 148 std::shared_mutex my_mutex; 149 }; // struct SharedMutexWrapper 150 151 int main() { 152 using map_type = oneapi::tbb::concurrent_hash_map<int, int, 153 oneapi::tbb::tbb_hash_compare<int>, 154 oneapi::tbb::tbb_allocator<std::pair<const int, int>>, 155 SharedMutexWrapper>; 156 157 map_type map; // This object will use SharedMutexWrapper for thread safety of insert/find/erase operations 158 } 159