(假设使用64位x86-64架构和英特尔第三/四代CPU)
以下是《并发实战》一书第202页中的无锁栈实现:
以下是《并发实战》一书第202页中的无锁栈实现:
template<typename T>
class lock_free_stack
{
private:
struct node;
struct counted_node_ptr
{
int external_count;
node* ptr;
};
struct node
{
std::shared_ptr<T> data;
std::atomic<int> internal_count;
counted_node_ptr next;
node(T const& data_):data(std::make_shared<T>(data_)),internal_count(0){}
};
std::atomic<counted_node_ptr> head;
public:
~lock_free_stack()
{
while(pop());
}
void push(T const& data)
{
counted_node_ptr new_node;
new_node.ptr=new node(data);
new_node.external_count=1;
new_node.ptr->next=head.load();
while(!head.compare_exchange_weak(new_node.ptr->next,new_node));
}
};
以下是代码下方的内容:
在支持双字比较和交换操作的平台上,此结构将足够小,以使std::atomic成为无锁状态。
我相信x86-64确实支持双重CAS(我暂时想不起指令的名称)。
如果我检查汇编代码(并且看不到双重CAS指令),那么我需要编写什么内联汇编函数来确保使用双重CAS?
更新 - 我想我在这里找到了我要找的内容:
http://blog.lse.epita.fr/articles/42-implementing-generic-double-word-compare-and-swap-.html
template<typename T>
struct DPointer <T,sizeof (uint64_t)> {
public:
union {
uint64_t ui[2];
struct {
T* ptr;
size_t count;
} __attribute__ (( __aligned__( 16 ) ));
};
DPointer() : ptr(NULL), count(0) {}
DPointer(T* p) : ptr(p), count(0) {}
DPointer(T* p, size_t c) : ptr(p), count(c) {}
bool cas(DPointer<T,8> const& nval, DPointer<T,8> const& cmp)
{
bool result;
__asm__ __volatile__ (
"lock cmpxchg16b %1\n\t"
"setz %0\n"
: "=q" ( result )
,"+m" ( ui )
: "a" ( cmp.ptr ), "d" ( cmp.count )
,"b" ( nval.ptr ), "c" ( nval.count )
: "cc"
);
return result;
}
// We need == to work properly
bool operator==(DPointer<T,8> const&x)
{
return x.ptr == ptr && x.count == count;
}
};
-mcx16
)在编译像std::atomic<my_struct>
这样的16B对象上的compare_exchange_weak
时,会使用LOCK CMPXCHG16B
。请参见此答案,其中我包含了使用(大部分)可移植的C++11代码实现它的示例。 - Peter Cordes