2016-05-18 76 views
2

上下文安全使用參考的

我有一個類(比方說Foo)管理的一些集中ressources作爲一個靜態地圖的歷史,與訪問者閱讀他們並添加新數據的功能(有沒有辦法刪除鍵):

class Foo 
{ 
    private: 
    static std::map<std::string,MyDataStructure> data; 
    public: 
    static const MyDataStructure& getData(const std::string& key) 
    { 
     assert(Foo::data.count(key) > 0); // Must exist 
     return Foo::data[key]; 
    } 
    static void addData(const std::string& key, const MyDataStructure& d) 
    { 
     assert(Foo::data.count(key) == 0); // Can not already exist 
     Foo::data[key] = d; 
    } 
}; 

爲了避免併發問題,我加了一個互斥我管理這樣的:

class Foo 
{ 
    private: 
    static std::map<std::string,MyDataStructure> data; 
    static boost::mutex mutex_data; 
    public: 
    static const MyDataStructure& getData(const std::string& key) 
    { 
     boost::mutex::scoped_lock lock(Foo::mutex_data); 
     assert(Foo::data.count(key) > 0); // Must exist 
     return Foo::data[key]; 
    } 
    static void addData(const std::string& key, const MyDataStructure& d) 
    { 
     boost::mutex::scoped_lock lock(Foo::mutex_data); 
     assert(Foo::data.count(key) == 0); // Can not already exist 
     Foo::data[key] = d; 
    } 
}; 

我的問題

  1. 我的第一個問題是關於參照Foo::datagetData返回:該參考使用了互斥的範圍,那麼是有可能有問題嗎?由於另一個訪問添加數據,是否可能丟失參考?簡而言之:地圖中的參考文獻總是一樣的嗎?
  2. 如果是,addData需要assert嗎?如果我更改鏈接到地圖中現有鍵的數據,引用是否可以更改?
  3. 是否需要鎖getData?我想也許不是如果std::map已經是多線程安全的。
+0

您是否在此使用斷言,因爲您的程序邏輯在添加數據之前不允許調用'getData',或者您正在使用它來檢查映射中是否存在數據? –

+0

@MohamadElghawi:它不是真的不允許使用,但顯然不是使用該對象的好方法。在我的程序中,「Foo :: data」是關於創建具有uniqid的對象的歷史記錄。嘗試訪問不存在的對象的歷史是沒有意義的。我使用'assert',因爲如果在釋放模式下創建並返回一個空的歷史記錄,這並不重要。 – Caduchon

+0

如果它不被禁止,那麼我會建議使用斷言以外的東西。斷言通常不會編譯到發佈版本中,因此您的支票在生產中不會停止。 –

回答

2
  1. 是能夠鬆開參考由於另一個訪問添加數據?簡而言之:地圖中的參考文獻總是一樣的嗎?

Lifetime of references in STD collections

「爲std::map時,引用有效,只要你不清除地圖,或刪除特定引用的元素;在插入或刪除其他元素是好的。」

  • 可以的,如果我改變鏈接到地圖現有密鑰數據的參考變化?
  • 根據上面的規則,沒有...修改已經在映射中的引用只是調整在相同地址的位。 (只要您不通過刪除密鑰實施修改,然後再次重新添加該密鑰。)

    1. getData中是否需要鎖定?我想也許不是如果std :: map已經是多線程安全的。

    參見C++11 STL containers and thread safety

    所以需要的鎖,因爲地圖結構的「內部佈線」可以期間addData()的插入是在磁通...這可能佈線的查找期間跳閘上遍歷getData()沒有警衛。

    但是,如果您掌握了參考資料,您可以在添加或刪除期間閱讀或編寫已經存在的MyDataStructure參考文獻之一。這只是從地圖到參考的導航過程,需要確保在導航過程中沒有人寫入。

    +0

    感謝這個清晰而好的答案。 :-) – Caduchon