这是一个c ++内联asm:
inline bool swap_if_null(head_t **p, head_t *np) {
register head_t *old;
asm volatile(
"lock;\n\t"
"cmpxchgq %3, %2"
: "=a"(old)
: "0"(0), "m"(*p), "r"(np)
: "memory");
return old == NULL;
}
答案 0 :(得分:3)
该函数正在*p
上进行原子比较和交换,预计处于状态np
,所需的新值为NULL
。该函数只执行一次,并返回操作是否成功。
一些解释:机器指令是lock cmpxchgq R, M
(在AT& T语法中),其中R
是包含新值的寄存器(它是与np
相关联的寄存器,如由“%3
”表示,即“第三个输入操作数”),M
是要修改的内存位置(即“%2
”,即“第二个输入操作数” “,即*p
)。
新值预计在寄存器%rax
中。该寄存器与作为第0个输出操作数的变量old
in相关联,但它也是"0"
引起的第一个输入操作数,这意味着“与第0个输入操作数相同”。但是在输入时,值不是绑定到变量,而是设置为“0
”。也就是说,%rax
最初为零,并且在指令old
引用它并包含操作结果之后。
根据比较和交换的性质,如果操作成功且%rax
保持不变,或者操作失败,则old
(以及%rax
)将为零内存的当前值为零。在这两种情况下,函数都会返回成功,即“头部现在为零”。
答案 1 :(得分:1)
inline bool swap_if_null(head_t **p, head_t *np) {
register head_t *old;
asm volatile(
"lock;\n\t"
"cmpxchgq %3, %2"
: "=a"(old)
: "0"(0), "m"(*p), "r"(np)
: "memory");
return old == NULL;
}
如果*p
为NULL,此函数将“交换”np
和*p
的内容。
它通过使用cmpxchgq
(比较和交换,四字[64位])指令来执行此操作,换句话说,比较*p
(%2
)处的64位值使用0
(在参数0中,即rax
),如果rax
值与内存位置匹配,则将新值存储在np
中,({{1 }})。最后,如果进行了替换,%3
包含内存位置中WAS的值,因此我们可以在替换时检查它是否为old
。 NULL
前缀确保处理器具有对内存的独占访问权限,目前没有其他处理器可以写入此位置。
这样做是为了避免在链接列表末尾插入内容时使用互斥锁。如果你有多个线程试图插入,你需要确保列表的末尾在你将元素添加到列表末尾的时候真的是NULL,否则事情就会出错(特别是列表会“丢弃“项目”。 lock
指令适用于这种“如果值为this,则将其替换为其他值”。