[英]Force copy (then destroy) on move-only type
考慮以下無鎖工作竊取(de)que函數:
template<class T>
inline T WorkStealQ<T>::Steal(void)
{
auto tail{_tail.load(std::memory_order_acquire)};
if (_head.load(std::memory_order_acquire) <= tail) return T();
auto task{_tasks[tail & _mask]};
if (_tail.compare_exchange_weak(tail, tail + 1, std::memory_order_release, std::memory_order_relaxed)) return task;
return T();
}
但是,如果T
僅可移動但不可復制該怎么辦? 問題是從緩沖區讀取項目是一項復制操作,無法更改為auto task{std::move(_tasks[tail & _mask])};
因為另一個並發操作也可以移動它,在這種情況下,任何非只讀但又修改原始操作的move構造函數(例如,使指向資源的指針為空)都會破壞算法。
請注意, Steal()
的整體語義僅從外部角度執行一次移動,因為只有一個並發操作將返回存儲在該位置的T
並返回。 輸掉比賽的其他任何人都將使compare_exchange_weak()
失敗。 因此,就用戶而言,該操作不會破壞僅可移動T
的語義。 不幸的是,在內部,它需要制作一個臨時的T
淺拷貝,直到確定是將其完成還是放棄后再將其保留在緩沖區中(這基本上是兩階段移動,中間進行檢查)。
一種實現方法是使T
副本構造函數和副本分配私有成員,並擁有一個friend WorkStealQ
。 問題是在我可能想用作T
的第三方庫類的情況下該怎么做。 在那種情況下,除了使用指向此類對象的指針而不是侵入性地存儲它們(從而導致性能下降)之外,還有其他選擇嗎? 我假設對於帶有虛函數的類,即使對於淺表副本, memcpy
也無法使用。
我認為最好的選擇可能是為每個T顯式定義一個單獨的shallow_copy類,並在工作竊取函數中使用該類。 這也將使您能夠處理任何導致您的類型變為僅移動的問題(因為您無法先驗地知道臨時副本可以避免這些問題)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.