2012-08-23 98 views
2

當我通過下面的代碼在MSVC 2012 步驟,我把在第3行和線路斷點8如何使用std :: lock_guard鎖定對std :: map的讀寫權限?

首先突破上線時8

的lock_guard被稱爲就好了,然後我們打破在第3行。 這一次,由於已經獲得了一個鎖,所以當我跨過時拋出一個異常。

我真的很喜歡它,以正義之舉,因爲它仍然在同一個線程調用(我們只是從線11來)

有另一種鎖定機制更適合這種情況?

我有一個本地win32編程的背景,所以我習慣了WaitForSingleObject,它只是讓我通過這裏沒有大驚小怪, 但lock_guard不。

我應該處理異常嗎?我見過的任何例子都沒有針對lock_guard的任何類型的異常處理程序...

有沒有更好的方法來確保地圖一次不會被多個線程訪問? 我需要寫和閱讀它鎖,lock_guard似乎是一個光滑的選擇,因爲我不必ReleaseMutex ...

//Cars.h 
    mutable std::mutex carsMutex; 
    class Cars 
    { 
    private: 
     std::map<std::string,Cars> _cars; 
    public: 
     virtual ~Cars() {} 
     Cars() {} 
     Cars & operator[](const std::string &key); 
     Cars & operator[](const DWORD &key); 
     std::string color; 
    }; 

    //Cars.cpp 
     #include "Cars.h" 
1. Cars & Cars::operator[](const std::string &key) 
2. { 
3.  std::lock_guard<std::mutex> lock_a(carsMutex); 
4.  return _cars[key]; 
5. } 
6. Cars & Cars::operator[](const DWORD &key) 
7. { 
8.  std::lock_guard<std::mutex> lock_a(carsMutex); 
9.  std::stringstream ss; 
10.  ss << key; 
11.  return operator[](ss.str()); 
12. } 
14. void main() 
15. { 
16.  //ok i have multiple threads like this one writing and reading from the map 
17.  Cars cars; 
18.  cars[(DWORD)2012]["volvo"].color = "blue"; 
19. } 

UPDATE: 這裏是我上面的代碼的編輯。 我已經考慮到了答案,這是我正確使用std :: lock_guard的新嘗試 如果不正確,請發表評論。

//Cars.h 
    mutable std::recursive_mutex carsMutex; 
    class Cars 
    { 
    private: 
     std::string _color; 
     std::map<std::string,Cars> _cars; 
    public: 
     virtual ~Cars() {} 
     Cars() {} 
     Cars & operator[](const std::string &key); 
     Cars & operator[](const DWORD &key); 
     void color(const std::string &color); 
     std::string color(); 
    }; 

     //Cars.cpp 
     #include "Cars.h" 
1. Cars & Cars::operator[](const std::string &key) 
2. { 
3.  std::lock_guard<std::recursive_mutex> lock(carsMutex); 
4.  return _cars[key]; 
5. } 
6. Cars & Cars::operator[](const DWORD &key) 
7. { 
8.  std::lock_guard<std::recursive_mutex> lock(carsMutex); 
9.  std::stringstream ss; 
10.  ss << key; 
11.  return operator[](ss.str()); 
12. } 
13. void color(const std::string &color) 
14. { 
15.  std::lock_guard<std::recursive_mutex> lock(carsMutex); 
16.  _color = color; 
17. } 
18. std::string color() 
19. { 
20.  std::lock_guard<std::recursive_mutex> lock(carsMutex); 
21.  return _color; 
22. } 
23. 
24. Cars cars;//this is global... 
25. void main() 
26. { 
27.  //ok i have multiple threads like this one writing and reading from the map 
28.  cars[(DWORD)2012]["volvo"].color("blue"); 
29. } 

回答

4

要允許一個線程重新獲取它已經擁有一個互斥體,你需要std::recursive_mutex而非std::mutex

但是,你有一個更大的問題:你的訪問者在之前解鎖互斥體返回你用來分配地圖元素的引用,所以分配本身是無防守的。這可以通過編寫一個在返回之前完成賦值的「setter」函數來解決;或者通過返回一個包含在其析構函數中釋放的互斥鎖的代理對象。解決這個問題可能會消除對recursive_mutex的需求。

+0

確定聽起來很有希望,但後來我得到這個錯誤:錯誤C2664:'std :: lock_guard <_Mutex> :: lock_guard(_Mutex&)':不能將參數1從'std :: recursive_mutex'轉換爲'std :: mutex &'我應該只投它嗎? – user1621065

+1

@ user1621065:你是否已經將lock guard改爲'lock_guard '?你有沒有讀過我更新的答案,這解釋了你認爲需要遞歸互斥體的更深層次的問題? –

+0

好吧,這是它:)謝謝,這麼簡單,但我無法弄清楚,除此之外,如果另一個線程試圖獲得鎖而鎖定它會拋出異常或只是等到鎖打開,然後輸入? – user1621065