2014-08-28 46 views
5

Potrzebuję stworzyć mapę bezpieczną dla wątków, gdzie mam na myśli to, że każda wartość musi być niezależnie muteksowana. Na przykład, muszę być w stanie uzyskać map["abc"] i map["vf"] w tym samym czasie z 2 różnych wątków.Mapa mutex C++ 11

Mój pomysł jest, aby dwie mapy: jeden dla danych i jeden dla mutex za każdy klucz:

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(); 
} 

Uważam, że nie można stworzyć mapę ze sznurkiem do mutex, ponieważ nie ma konstruktora kopia w std::mutex i muszę użyć std::unique_ptr; ale gdy skompiluję to otrzymuję:

/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>); 
                 ^

Jak rozwiązać ten problem?

Odpowiedz

9

Wymień mutexCache.insert(new std::unique_ptr<std::mutex>) z:

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

w C++ 14, należy powiedzieć:

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

Ogólny kod jest bardzo głośny i nieeleganckie, choć. Powinno to prawdopodobnie wyglądać następująco:

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]; 
    } 
} 
+1

+1 dla 'std :: make_unique ' –

+3

FWIW, należy użyć 'make_unique' w C++ 11 też. –

4

Dlaczego trzeba użyć std::unique_ptr w pierwszej kolejności?

Miałem ten sam problem, gdy musiałem utworzyć obiekty std::map z obiektów std::mutex. Problem polega na tym, że std::mutex nie jest ani kopiowalny ani ruchomy, więc musiałem go skonstruować "na miejscu".

Nie mogłem po prostu użyć emplace, ponieważ nie działa bezpośrednio dla wartości skonstruowanych domyślnie. Istnieje możliwość korzystania std::piecewise_construct takiego:

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

ale IMO skomplikowany i mniej czytelny.

Moje rozwiązanie jest znacznie prostsze - po prostu użyj operator[] - utworzy wartość używając domyślnego konstruktora i zwróci do niej odwołanie. Lub po prostu znajdzie i zwróci odniesienie do już istniejącego przedmiotu bez tworzenia nowego.

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 
}