确保使用双比较和交换指令,为无锁堆栈
Ensuring usage of double-compare-and-swap instruction, for lock-free stack?
(假设64位x86-64架构和Intel第三/第四代CPU)
这是一个栈的无锁实现,来自Action中的Concurrency,第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-.htmltemplate<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 %1nt"
"setz %0n"
: "=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;
}
};
旧版本的x86_64不支持此指令(CMPXCHG16B),这是Windows 8.1/64位及更新版本所必需的。Afaik这是大多数Athlon64系列(插座751,939和一些X2,也许是第一代(8xx)的Pentium D太)
强制编译器使用某个指令的方法各不相同,通常必须使用不完全可移植的内在指令。
你可以断言
std::atomic<T>::is_lock_free()
相关文章:
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 无法编译 rtmidi 测试 cmidiin.cpp 文件, 非法指令
- C++:对不存在的命名空间使用命名空间指令
- 算法问题:查找从堆栈中弹出的所有序列
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 函数名是c中该函数的第一条指令的地址吗
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- 为什么调用堆栈数组会导致内存泄漏
- gdb错误:Backtrace已停止:上一帧与此帧相同(堆栈已损坏?)
- 错误:无效的预处理指令 #i 的意思是 #if?
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 组装指令中乘法的下部和上部是什么
- 堆栈和队列是否像C++中的数组一样传递?
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 为什么 STL 容器适配器堆栈中的 top 返回常量引用?
- 从堆栈分配的原始指针构造智能指针
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 旧警告:堆栈子指令与OS X上的矮人堆栈大小差异太大
- 确保使用双比较和交换指令,为无锁堆栈