【发布时间】:2016-06-10 02:48:47
【问题描述】:
我正在尝试用我的 C 代码编写内联汇编来执行比较和交换操作。我的代码是:
typedef struct node {
int data;
struct node * next;
struct node * backlink;
int flag;
int mark;
} node_lf;
typedef struct searchfrom {
node_lf * current;
node_lf * next;
} return_sf;
typedef struct csArg {
node_lf * node;
int mark;
int flag;
} cs_arg;
typedef struct return_tryFlag {
node_lf * node;
int result;
} return_tf;
static inline node_lf cs(node_lf * address, cs_arg *old_val, cs_arg *new_val)
{
node_lf value = *address;
__asm__ __volatile__("lock; cmpxchg16b %0; setz %1;"
:"=m"(*(volatile node_lf *)address),
"=q"(value)
:"m"(*(volatile node_lf *)address),
"a"(old_val->mark), "d"(old_val->flag),
"b"(new_val->mark), "c"(new_val->flag)
:"memory");
return value;
}
编译代码时GCC会报这个错误:
linkedlist.c:在函数“cs”中:linkedlist.c:45:3:错误:“asm”中不可能的约束
__asm__ __volatile__("lock; cmpxchg16b %0; setz %1;":"=m" (*(volatile node_lf
我的代码有什么问题?我该如何解决这个问题?
我正在尝试实现此代码的等效项:
node_lf cs (node_lf * address, cs_arg *old_val, cs_arg *new_val ) {
node_lf value = *address;
if (value.next == old_val->node && value.mark == old_val->mark &&
value.flag == old_val->flag) {
address->next = new_val->node;
address->mark = new_val->mark;
address->flag = new_val->flag;
}
return value;
}
【问题讨论】:
-
代码和错误信息应该在问题本身中。
-
具体问题是 x86 上的 'q' 约束必须是 a/b/c/dx,但您已经将所有这些用于其他参数。也就是说,我想推动不使用内联汇编。使用 __sync_bool_compare_and_swap 怎么样?甚至可能是 std::atomic?
-
我认为可能真正发生的事情是
node_lf value将值定义为一种数据结构(而不是指向一个的指针)并且不适合 64 位寄存器。你真的是想用那种方式传递value吗? -
@PeterCordes :是的,它是经过 OCR 处理的,比手动操作要好 ;-)。我必须修复很多东西,但我错过了错误消息中的小写
L之一。但是我相信代码本身是相当准确的。我确实在我的一个 cmets 中指出了value的问题,询问 OP 是否真的打算做他们正在做的事情(显然他们不应该这样做)。 -
@MichaelPetch - 是的,你是对的:问题在于他按值返回结构。好吧,再加上他试图用
setz设置结构的值?value将包含一个布尔值,指示 cmpxchg16b 是否成功。
标签: c gcc x86-64 inline-assembly lock-free