[英]Is shared_ptr::unique() indicative that only one thread owns it?
我有一個工作線程給我的渲染線程一個std::shared_ptr<Bitmap>
作為我如何從 GPU 下載紋理數據的一部分。 兩個線程都依賴於std::shared_ptr<...>::unique()
來確定另一個線程是否完成了位圖。 此共享指針沒有其他副本在起作用。
這是行為的精簡圖表:
worker thread | rendering thread
----------------------------------- + -------------------------------------------------
std::shared_ptr<Bitmap> bitmap; | std::queue<std::shared_ptr<Bitmap>> copy;
{ | {
std::scoped_lock lock(mutex); | std::scoped_lock lock(mutex);
queue.push_back(bitmap); | std::swap(queue, copy);
} | }
... | for(auto it = copy.begin(); it != copy.end(); ++it)
| if (it->unique() == false)
if (bitmap.unique()) | fillBitmap(*it); // writing to the bitmap
bitmap->saveToDisk(); // reading
使用unique()
或use_count() == 1
來完成此操作是否安全?
編輯:
啊...因為在這種情況下unique()
是不安全的,所以我想我會嘗試類似std::shared_ptr<std::pair<Bitmap, std::atomic<bool>>> bitmap;
相反,當它被填充時翻轉原子。
不,這不安全。 對unique
(或use_count
)的調用並不意味着任何同步。
例如,如果工作線程將bitmap.unique()
觀察為true
,這並不意味着對fillBitmap(*it);
以及那些由bitmap->saveToDisk();
. 函數調用可以實現為寬松的負載,它沒有所需的獲取-釋放效果。
如果沒有任何內存排序,您可能會遇到數據競爭和未定義的行為。
這就是為什么std::shared_ptr::unique
在 C++17 中被棄用並在 C++20 中被移除的原因,因為它很容易以這種方式被濫用。 僅使用use_count() == 1
也不起作用。 它有完全相同的問題。 我想它也沒有被刪除,因為即使在多線程環境中也可能有有效的用例use_count
如果你只需要它來模糊地了解當前用戶的數量並且因為仍然應該有一種方法為單線程上下文實現unique
(沒有任何問題)。
根據刪除std::shared_ptr::unique
的提議,許多實現實際上確實使用了寬松的負載,這意味着問題實際上可能發生在實際實現中,請參閱https://open-std.org/jtc1/sc22/wg21 /docs/papers/2016/p0521r0.html 。
如果您在 x86 之類的體系結構上,您可能會因為在硬件級別上的輕松負載自動成為獲取負載這一事實而節省您的時間。
但是,C++ 內存模型在這里沒有做出任何排序保證,我認為(在這里可能是錯誤的)例如 ARM 是正常(寬松)負載不會自動具有獲取/釋放語義的架構的示例。
無論如何,由於沒有內存排序保證,我認為編譯器仍然可以執行在任何情況下都會導致問題的轉換。 例如,因為unqiue
不暗示任何同步,編譯器可以加載bitmap->saveToDisk();
在實際加載引用計數器之前。 如果引用計數器上的條件被證明沒有得到滿足,則加載可能是不必要的,但我沒有看到任何阻止編譯器添加多余負載的東西。
在這些之間從fillBitmap(*it);
並且可能發生渲染線程std::shared_ptr
的破壞,導致工作線程使用存儲在fillBitmap(*it);
.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.