Mutex C ++ 11 Card

I need to create a thread safe map where I mean that each value must be independently mutexed. For example, I need to be able to get map["abc"] and map["vf"] simultaneously from two different streams.

My idea is to create two cards: one for data and one for a mutex for each key:

 class cache { private: .... std::map<std::string, std::string> mainCache; std::map<std::string, std::unique_ptr<std::mutex> > mutexCache; std::mutex gMutex; ..... public: std::string get(std::string key); }; std::string cache::get(std::string key){ std::mutex *m; gMutex.lock(); if (mutexCache.count(key) == 0){ mutexCache.insert(new std::unique_ptr<std::mutex>); } m = mutexCache[key]; gMutex.unlock(); } 

I find that I cannot create a map from a string to a mutex because there is no copy constructor in std::mutex , and I have to use std::unique_ptr ; but when I compile this, I get:

 /home/user/test/cache.cpp:7: error: no matching function for call to 'std::map<std::basic_string<char>, std::unique_ptr<std::mutex> >::insert(std::unique_ptr<std::mutex>*)' mutexCache.insert(new std::unique_ptr<std::mutex>); ^ 

How to solve this problem?

+5
source share
2 answers

Replace mutexCache.insert(new std::unique_ptr<std::mutex>) with:

 mutexCache.emplace(key, new std::mutex); 

In C ++ 14 you should say:

 mutexCache.emplace(key, std::make_unique<std::mutex>()); 

The general code is very noisy and inelegant. It should probably look like this:

 std::string cache::get(std::string key) { std::mutex * inner_mutex; { std::lock_guard<std::mutex> g_lk(gMutex); auto it = mutexCache.find(key); if (it == mutexCache.end()) { it = mutexCache.emplace(key, std::make_unique<std::mutex>()).first; } inner_mutex = it->second.get(); } { std::lock_guard<std::mutex> c_lk(*inner_mutex); return mainCache[key]; } } 
+9
source

Why would you use std::unique_ptr ?

I had the same problem when I had to create std::map objects from std::mutex . The problem is that std::mutex is neither copyable nor movable, so I needed to build it "in place".

I could not just use emplace , because it does not work directly for default values. It is possible to use std::piecewise_construct as follows:

 map.emplace(std::piecewise_construct, std::make_tuple(key), std::make_tuple()); 

but it is IMO complicated and less readable.

My solution is much simpler - just use operator[] - it will create a value using its default constructor and return a link to it. Or he just finds and returns a link to an existing element without creating a new one.

 std::map<std::string, std::mutex> map; std::mutex& GetMutexForFile(const std::string& filename) { return map[filename]; // constructs it inside the map if doesn't exist } 
+4
source

Source: https://habr.com/ru/post/1201315/


All Articles