2016-04-05 103 views
0

參考返回值我有一個非常相似的問題已經問2012年臨界區,並在C++

Critical Sections and return values in C++

我想訪問一個容器線程安全的藏漢而是通過引用返回緩存的版本。

struct Container { 
    const Data& getSomeData() const { 
    EnterCriticalSection(& myCritSec); 
    if (update) { 
     cache.calulatefromcontainer();   
    } 
    // fill retobj with data from structure 
    LeaveCriticalSection(& myCritSec); 
    return cache; 
    } 

private: 
    mutable Data cache; 
}; 

問題是,「返回緩存」行不再受到保護。是否有可能通過引用返回「緩存」線程安全?

+2

返回對可修改數據的引用基本上是對線程安全容器的禁用。這裏並沒有多少意思。 – SergeyA

回答

0

你必須考慮你的關鍵部分實際上保護着什麼。

在您的代碼中,它看起來像myCritSec正在保護容器。但值得注意的是,它是而不是保護cache成員變量。這不是因爲return cache;行,而是因爲您返回對它的引用,所以它可以不受客戶端代碼的限制使用,而其他線程再次調用getSomeData()並對其進行修改。

一種解決方案是返回數據的副本。

另一種解決方案是,每個用於從Data獲取信息的公共函數都會使用父容器的myCritSec。這種方法的問題是,這將是很容易陷入種族。例如:

class Data 
{ 
public: 
    int getA() const 
    { 
     int res; 
     EnterCriticalSection(parentCS); 
     res = getAunlocked(); 
     LeaveCriticalSection(parentCS); 
     return res; 
    } 
    int getB() const 
    { 
     int res; 
     EnterCriticalSection(parentCS); 
     res = getBunlocked(); 
     LeaveCriticalSection(parentCS); 
     return res; 
    } 
}; 

然後在用戶代碼:

const Data &data = container.getSomeData(); 
if (data.getA() == data.getB()) // <--- RACE!!! 
{ 
} 

由於調用getA()getB()分別鎖定和解鎖CS,另一個線程可能會修改只是在兩者之間並創建數據競賽狀況。

+0

那麼唯一真正安全的解決方案是數據的副本? –

+0

@vcduser:「唯一真正安全的解決方案」?有很多方法可以做正確的事情。例如,您可以將CS處理代碼添加到容器的用戶,例如,如果您可以信任它的話。或者您可以複製數據的子集,或者您可以使用寫時複製技術,共享指針...... – rodrigo