1

这是一个 C++ 内联汇编:

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;
}
4

2 回答 2

3

该函数正在对 进行原子比较和交换*p,预计该状态为np,并且所需的新值为NULL。该函数只执行一次并返回操作是否成功。

一些解释:机器指令是lock cmpxchgq R, M(在 AT&T 语法中),其中R是包含新值的寄存器(它是与 关联的寄存器np,如“ %3”所示,即“第三输入操作数”),并且M是内存位置被修改(即“ %2”,即“第二个输入操作数”,即*p)。

新值应该在寄存器中%rax。该寄存器与变量oldin 作为第 0 个输出操作数相关联,但由于 ,它也是第一个输入操作数"0",这意味着“与第 0 个输入操作数相同”。但在输入时,该值并未绑定到变量,而是设置为“ 0”。也就是说,%rax最初为零,并且在指令old引用它并包含操作结果之后。

根据比较和交换的性质,如果操作成功并且保持不变,或者操作失败并且内存的当前值为零,则%rax(因此old)将为零。在这两种情况下,函数都返回成功,即“头部现在为零”。%rax

于 2013-08-21T00:04:11.780 回答
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;
}

如果为 NULL *p,此函数将“交换” 的内容。np*p

它通过使用cmpxchgq(Compare and Exchange, quadword [64 bits]) 指令来做到这一点,换句话说,将*p( %2) 处的 64 位值与0(在参数 0 中,即rax) 进行比较,如果该rax值与内存匹配位置,将新值存储在np, ( %3) 中。最后,old如果进行了替换,则包含内存位置中的 WAS 值,因此我们可以检查它NULL在被替换时是否为 WAS。lock前缀确保处理器具有对内存的独占访问权限,目前没有其他处理器可以写入该位置 。

这样做是为了避免在链表末尾插入某些内容时使用互斥锁。如果有多个线程试图插入,则需要确保在将元素添加到列表末尾时,列表末尾确实为 NULL,否则会出错(特别是列表将“掉落”物品)。该cmpxchg指令是针对这种“如果值是这个,用这个另一个值替换它”。

于 2013-08-21T00:04:23.060 回答