2014-03-31 103 views
1

我有一個類,包括一個地圖和一個互斥體。在每一個成員函數互斥體保護從多個線程訪問這個類的對象可在地圖,爲前:如何避免重複的代碼,包括std :: map和std :: mutex

class bar 
{ 
public: 
    void hello() {} 
    void set_something(int x) {} 
    int get_something(int x, int y) { return x + y; } 
}; 

class foo 
{ 
public: 
    foo() 
    { 
     m_map[0]; 
     m_map[1]; 
     m_map[2]; 
    } 
    void hello(unsigned int index) 
    { 
     std::lock_guard<std::mutex> lock(m_mut); 
     const auto iter = m_map.find(index); 
     if (iter != m_map.end()) 
      iter->second.hello(); 
    } 
    void set_something(unsigned int index, int x) 
    { 
     std::lock_guard<std::mutex> lock(m_mut); 
     const auto iter = m_map.find(index); 
     if (iter != m_map.end()) 
      iter->second.set_something(x); 
    } 
    int get_something(unsigned int index, int x, int y) 
    { 
     std::lock_guard<std::mutex> lock(m_mut); 
     const auto iter = m_map.find(index); 
     if (iter != m_map.end()) 
      return iter->second.get_something(x, y); 
     return 0; 
    } 
private: 
    std::mutex     m_mut; 
    std::map<unsigned int, bar> m_map; 
}; 

有一種優雅的方法,以避免重複的代碼?

回答

4

你可以使用代理服務器RAII這樣的:

#include <iostream> 
#include <mutex> 
#include <map> 

template < typename F, typename S> 
struct mutex_map { 
    std::recursive_mutex m_; 
    std::map<F,S> map_; 

    struct Proxy { 
     Proxy(std::map<F,S> & map, std::recursive_mutex &m) : map_(&map), lock_(m) { 
      std::cout << "lock\n"; 
     } 
     ~Proxy() { std::cout << "unlock\n"; } 
     std::map<F,S>* map_; 
     std::unique_lock<std::recursive_mutex> lock_; 

     std::map<F,S>* operator->() { return map_; } 
    }; 

    Proxy operator->() { 
     return { map_, m_ }; 
    } 
}; 

int main() { 
    mutex_map<int, int> mm; 

    mm->emplace(1, 3); 
    std::cout << (mm->find(1) == mm->end()) << "\n"; 
    std::cout << (mm->find(2) == mm->end()) << "\n"; 
} 
+0

使用代理模式爲此非常棒!如果我的示例使用std :: shared_mutex而不是std :: mutex,它也可以工作嗎? – cbel

2

您可以將常用的部分爲「do_something」,並通過仿函數到其中:

... 
void do_something(const std::function<void(bar&)>& func) 
{ 
    std::lock_guard<std::mutex> lock(m_mut); 
    const auto iter = m_map.find(index); 
    if (iter != m_map.end()) 
     func(std::ref(*iter)); 
} 

int get_something(unsigned int index, int x, int y) 
{ 
    do_something(std::bind(&bar::get_something, std::placeholders::_1, index, x, y)); 
} 
... 

一個問題 - 你需要保護與互斥唯一的std ::地圖或std ::地圖和它的要素是什麼?你可能會認爲有關粒度

+0

我只是代碼的簡單代碼。在我的情況下,我只保護std :: map並實際使用ting :: shared_mutex(std :: shared_mutex)。謝謝你的回答! – cbel

+0

一切都是可能的,如果你想區分用於寫入的鎖和用'shared_timed_mutex'來讀取鎖,你應該在'mutex_map'中放置通用的'operator->'並添加兩個不同的獲取函數,並返回一個不同的代理鎖定你想要的。請注意,我的例子只是代理想​​法的展示。 – galop1n

+0

對不起,但我認爲這個答案對我來說也很棒! – cbel