// Thread 1:
sharedMemory = std::make_shared<Immutable>(1);
// Thread 2:
DoSomething(*sharedMemory);
這不是一個不變性的例子。 sharedMemory
的共享狀態是而不是不可變。
不變性是兩個不同的線程都讀sharedMemory
構建前或者線程存在。
如果他們想對其進行更改,他們返回的變化。
不變性意味着所有共享狀態不能改變。您仍然可以將數據傳遞到線程(通過線程參數),或將數據從線程傳遞出去(通過future
)
您甚至可以製作獨立的可變共享狀態,就像工作線程使用的任務隊列一樣。這裏的隊列本身是可變的,並且是精心編寫的。該工作線程佔用的任務。
但任務只有一成不變的共享狀態下工作,他們通過future
是排隊的任務返回的數據返回給其他線程。
可變性的軟形式是期貨。
std::shared_future<std::shared_ptr<Immutable>> sharedMemory = create_shared_memory_async();
std::future<void> r = DoSomethingWithSharedMemoryAsync(sharedMemory);
// in DoSomethingWithSharedMemory
auto sharedMemoryV = sharedMemory.get(); // blocks until memory is ready
DoSomething(*sharedMemory);
這不是完全不可變的共享狀態。
這裏是另一個不純使用不可改變的共享狀態的:
cow_ptr<Document> ptr = GetCurrentDocument();
std::future<error_code> print = print_document_async(ptr);
std::future<error_code> backup = backup_document_async(ptr);
ptr.write().name = "new name";
一個cow_ptr
是寫指針的副本。它允許只讀不可變的訪問。
如果你想改變它,你可以調用.write()
方法。如果你是唯一擁有共享資源的人,它只是給你寫權限。否則,它克隆資源並確保它是唯一的,然後爲您提供寫入權限。
兩個不同的線程,print
和backup
線程可以訪問ptr
。他們不能更改任何其他線程可以看到的數據(允許編輯它們,但只會修改其本地數據副本)。
回到主線程中,我們將文檔重命名爲新名稱。打印線程和備份線程都不會看到這一點,因爲它們具有不可變(邏輯)副本。
兩個線程訪問相同的ptr
變量是不合法的,但他們可以訪問複製ptr
變量。
如果文檔本身全部由cow_ptr
構建而成,則該文檔的「副本」將僅複製內部cow_ptr
;即它會原子增加一些參考計數,而不是整個狀態。
修改深層元素將涉及麪包屑;你會想要一個breadcrumb_ptr
,記錄達到給定的cow_ptr
所需的路線。然後,.write()
將繼續複製所有內容到「文檔」的根目錄,可能會替換每個指針(使用.write()
調用)。
在這個系統下,我們有能力在線程之間共享O(1)代價的非常大且複雜的數據結構shapeshot,唯一的同步開銷就是引用計數。
這仍然不是純粹的不變性。但在實踐中,這種不可變性的不純形式帶來了許多好處,並允許您有效且安全地完成極其危險或昂貴的事情。
我認爲這個想法是在開始多線程之前設置共享對象。 – Justin