2017-09-25 82 views
1

我擁有包裝在shared_ptr中的資源「resource」,並且我想從其他線程訪問它。 當我這樣做:C++返回函數lock_guard

// foo.h 
class Foo{ 
public: 
    std::shared_ptr<Setup> GetSomeThing(); 
    void SetSomeThing(); 
private: 
    std::shared_ptr<Setup> resource; 
    std::mutex lock; 
} 
//Foo.cpp 
std::shared_ptr<Setup> Foo::GetSomeThing() 
{ 
    std::lock_guard<std::mutex> lock (mutex); 
    return resource; 
} 

void Foo::SetSomeThing() 
{ 
    std::lock_guard<std::mutex> lock (mutex); 
    resource = ...; 
} 

這一切都好嗎? 什麼時候會創建一個返回對象,什麼時候會被銷燬?它在文檔中是否存在一些關於它的內容? 謝謝!

+4

'lock'會在範圍退出時被銷燬,所以它是完全沒有意義的。相反,調用線程應該創建這個鎖,然後調用'Foo :: GetSomeThing'並處理相同(或內部)範圍內的某些內容,同時'lock'仍然存在。 – VTT

+1

您需要在所有線程之間使用常見的互斥鎖,並且在所有線程中也使用lock_guard或類似鎖。例如Foo還應該有一個std :: mutex _mtxResource - 然後std :: lock_guard lock(foo._mtxResource);無論你需要在你的線程中使用資源。 –

+0

@VTT請再次看到代碼示例)它仍然毫無意義? – voltento

回答

1

此答案假定(爲了清楚起見),所述兩行:

std::lock_guard<std::mutex> lock (mutex); 

都與

std::lock_guard<std::mutex> guard (lock); 

替換如果多個線程存取的std::shared_ptr<>單個實例不同步和任何那些呼叫的非const成員則發生數據競爭。

這意味着您必須確保SetSomeThing()GetSomething()之間的同步。

介紹一個std::mutex和使用std::lock_guard<>在提出的方式將做到這一點。返回的副本將在調用guard的析構函數之前構建。

請注意它是關於相同的實例。由GetSomeThing()返回的副本具有足夠的內部同步以確保可以訪問(非const甚至被破壞)而無需同步其他實例。

但是,這些都不能阻止std::shared_ptr<Setup>擁有的任何共享Setup對象(part-)上的數據競爭。如果對Setup的所有訪問都是隻讀的,則多個線程都可以訪問它,但是如果有任何線程寫入共享數據,就會發生數據競爭(沒有未在問題中顯示的進一步同步)。

在一個簡單的應用程序中,像Setup這樣的對象可能會在多線程啓動和初始化之前,當除主線程之外的所有線程都已終止。在這種特定情況下,不需要進一步的同步,甚至提供的鎖也是多餘的。

這裏有一個非規範的參考:

http://en.cppreference.com/w/cpp/memory/shared_ptr

參考開說明的最後一段。

腳註:更改應用程序「設置」可能比簡單地確保數據競爭不會在屬性上發生更困難。線程可能需要採用更改或「放棄」活動。例如,考慮一個圖形程序,其中屏幕分辨率在「繪圖」步驟中更改。是否應該完成繪製並製作過大/過小的畫布或轉儲繪製的部分畫布並採用新的分辨率?這種設置是否以這樣的方式獲得,即平局會產生與'之前'或'之後'一致的東西,而不是某些無意義的(可能是崩潰的)混合體?