2014-08-28 16 views
5

Tôi cần tạo một bản đồ an toàn cho luồng, trong đó tôi có nghĩa là mỗi giá trị phải được tắt tiếng độc lập. Ví dụ, tôi cần để có thể nhận được map["abc"]map["vf"] cùng một lúc từ 2 chủ đề khác nhau.Bản đồ của mutex C++ 11

Ý tưởng của tôi là làm cho hai bản đồ: một cho dữ liệu và một cho mutex cho mỗi phím:

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

tôi thấy rằng tôi không thể tạo bản đồ từ chuỗi mutex, vì không có constructor sao chép trong std::mutex và tôi phải sử dụng std::unique_ptr; nhưng khi tôi biên dịch, tôi nhận được:

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

Làm cách nào để giải quyết vấn đề này?

Trả lời

9

Thay mutexCache.insert(new std::unique_ptr<std::mutex>) với:

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

Trong C++ 14, bạn nên nói:

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

Mã tổng thể là rất ồn ào và không thanh nha, mặc dù. Có thể có vẻ như sau:

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 cho 'std :: make_unique ' –

+3

FWIW, bạn nên sử dụng' make_unique' trong C++ 11 quá. –

4

Tại sao bạn cần sử dụng số std::unique_ptr ngay từ đầu?

Tôi đã gặp vấn đề tương tự khi tôi phải tạo một đối tượng std::map của std::mutex. Vấn đề là std::mutex không thể sao chép cũng như không thể di chuyển được, vì vậy tôi cần phải xây dựng nó "tại chỗ".

Tôi không thể sử dụng emplace vì nó không hoạt động trực tiếp cho các giá trị được tạo mặc định. Có một tùy chọn để sử dụng std::piecewise_construct như thế:

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

nhưng IMO phức tạp và ít có thể đọc được.

Giải pháp của tôi đơn giản hơn nhiều - chỉ cần sử dụng operator[] - nó sẽ tạo giá trị bằng cách sử dụng hàm tạo mặc định của nó và trả về một tham chiếu đến nó. Hoặc nó sẽ chỉ tìm và trả lại một tham chiếu đến mục đã tồn tại mà không cần tạo một mục mới.

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 
} 
Các vấn đề liên quan