以下代码是取自PARSEC benchmark suite for shared-memory multiprocessors中模拟退火应用程序的原子指针类的骨架。
在该应用中,中央数据结构是图形(更具体地,是集成电路的网表)。图中的每个节点都有一个指示其物理位置的属性。该算法重复产生许多线程和每个线程,并随机选择两个节点并交换它们的物理位置,如果这样可以为芯片带来更好的路由成本。
因为图形很大并且每个线程都可以选择任何一对节点,所以唯一可行的解决方案是无锁并发数据结构(CDS)。这就是为什么以下AtomicPtr
类是至关重要的(它用于以无锁方式原子地交换指向两个物理位置对象的指针)。
函数atomic_load_acq_ptr()
是在汇编代码中定义的,与std::atomic<T*>::load(memory_order_acquire)
紧密对应。
我想使用C ++ 11 atomics实现该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()
方法只能用于与T*
对象交换裸std::atomic<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*>
个对象。有什么想法吗?
答案 0 :(得分:5)
在我看来,获得你想要的更简单的方法是复制你在这里看到的逻辑。
问题在于不可能跨两个原子对象进行原子操作,所以你必须遵循一个过程:
这当然是非常不完美的:
然而,在仅有2个物体的情况下,它应该在实践中相对较好(因此可以锁定一个物体)。
最后,我有两点评论:
0x01
通常适用于指针。std::atomic<T*>
无锁定,您可以使用std::atomic<T*>::is_lock_free()
检查此特定实施和平台。答案 1 :(得分:2)
没有螺旋锁的最接近的是:
std::atomic<T> a;
std::atomic<T> b;
a = b.exchange(a);
b
的线程安全。
a
可能无法同时访问。
答案 2 :(得分:0)
您是否检查了CAS(比较和交换)操作?
std::atomic<T*> v;
while(!v.compare_exchange_weak(old_value,new_value, std::memory_order_release, memory_order_relaxed))