[英]Why don't standard libraries implement std::atomic for structs under 8 bytes in a lock-free manner?
[英]Atomic exchange of two std::atomic<T*> objects in a lock-free manner in C++11?
以下代碼是一個原子指針類的框架,它取自PARSEC基准套件中用於共享內存多處理器的模擬退火應用程序。
在該應用中,中央數據結構是圖(更具體地,集成電路的網表)。 圖中的每個節點都有一個指示其物理位置的屬性。 該算法產生許多線程並且每個線程重復並隨機選擇兩個節點並交換它們的物理位置,如果這導致芯片的更好的路由成本。
因為圖形很大並且每個線程都可以選擇任何一對節點,所以唯一可行的解決方案是無鎖並發數據結構(CDS)。 這就是為什么以下AtomicPtr
類是至關重要的(它用於以無鎖方式原子地交換指向兩個物理位置對象的指針)。 函數atomic_load_acq_ptr()
是在匯編代碼中定義的,並且與std::atomic<T*>::load(memory_order_acquire)
緊密對應。
我想用C ++ 11原子實現該CDS。
template <typename T>
class AtomicPtr {
private:
typedef long unsigned int ATOMIC_TYPE;
T *p __attribute__ ((aligned (8)));
static const T *ATOMIC_NULL;
inline T *Get() const {
T *val;
do {
val = (T *)atomic_load_acq_ptr((ATOMIC_TYPE *)&p);
} while(val == ATOMIC_NULL);
return val;
}
inline void Swap(AtomicPtr<T> &X) {
// Define partial order in which to acquire elements to prevent deadlocks
AtomicPtr<T> *first;
AtomicPtr<T> *last;
// Always process elements from lower to higher memory addresses
if (this < &X) {
first = this;
last = &X;
} else {
first = &X;
last = this;
}
// Acquire and update elements in correct order
T *valFirst = first->Checkout(); // This sets p to ATOMIC_NULL so all Get() calls will spin.
T *valLast = last->PrivateSet(valFirst);
first->Checkin(valLast); // This restores p to valLast
}
};
std::atomic<T*>::exchange()
方法只能用於與std::atomic<T*>
對象交換裸T*
指針。 如何以無鎖方式交換兩個std::atomic<T*>
對象?
我能想到的是下面的AtomicPtr
類本身可以基於std::atomic<T*>
來聲明:
std::atomic<T*> p;
和更換所有atomic_load_acq_ptr()
通過調用std::atomic<T*>::load(memory_order_acquire)
和替換所有atomic_store_rel_ptr()
通過調用std::atomic<T*>::store(memory_order_release)
但我的第一個想法是std::atomic<T*>
應該取代AtomicPtr
本身,並且可能有一種聰明的方式直接交換std::atomic<T*>
對象。 有什么想法嗎?
在我看來,獲得你想要的更簡單的方法是復制你在這里看到的邏輯。
問題是不可能跨兩個原子對象獲取原子操作,因此您必須遵循以下過程:
當然,這非常不完美:
然而,在僅有2個物體(因此鎖定一個物體)的情況下,它在實踐中應該相對較好地工作。
最后,我有兩個評論:
0x01
通常適用於指針。 std::atomic<T*>
是無鎖的,你可以使用std::atomic<T*>::is_lock_free()
來檢查你的特定實現和平台。 沒有螺旋鎖的最接近的是:
std::atomic<T> a;
std::atomic<T> b;
a = b.exchange(a);
哪個是b
線程安全。
a
可能無法同時訪問。
你檢查了CAS(比較和交換)操作嗎?
std::atomic<T*> v;
while(!v.compare_exchange_weak(old_value,new_value, std::memory_order_release, memory_order_relaxed))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.