原子商店。结构

时间:2016-07-21 22:30:45

标签: c++ multithreading assembly x86

我编译并分析了汇编输出:

struct S{
public:
    int a,b,c,d,e,f,g,h,i,j,k;
};

int main() {
    S s;
    std::atomic<S> as;
    as.store(s);
    return 0;
}

我想知道它实际上是如何实现的atomic store。对齐&#34;小&#34;它很容易。操作数。但是,现在我们有一个更广泛的操作数,所以这是一个更复杂的情况。

在我的另一个问题(Atomicity on x86)中@Peter Cordes说:

  

对于更广泛的操作数,例如原子地将新数据写入多个   一个结构的条目,你需要用一个锁来保护它   访问它尊重。 (您可以使用x86 lock cmpxchg16b   使用重试循环来执行原子16b存储。请注意,没有办法   在没有锁定的情况下模仿它。)

好的,但这究竟是什么意思?锁定是什么意思? 特别是,我知道lock是一个前缀,可以确保&#34;前缀&#34;的原子性。指令。特别是@Peter Cordes说:

  

您可以使用x86 lock cmpxchg16b   使用重试循环来执行原子16b存储

我无法理解如何将其保持原子状态?好吧,我可以想象16B的内存块可以以原子方式存储吗?但是下一次迭代呢?

我希望我的怀疑是可以理解的,因为我有一个问题要表达它。

我正在调试上面的程序,在我的眼里,魔法在atomic_store之后。 我想这个函数执行的是@Peter Cordes所说的。如果有人想要,我可以在这里粘贴反汇编__atomic_store

1 个答案:

答案 0 :(得分:3)

  

您可以使用x86 lock cmpxchg16b和重试循环来执行原子16B存储

我真的说16b而不是16B吗?哎呀。我会将其作为更大编辑的一部分来解决。

这可以让你做一个 16B原子存储,但是它作为一个读取 - 修改 - 重写,一直保持重试,直到比较部分成功。您不能使用它以原子方式存储超过16B。

  

锁定是什么意思?特别是,我知道lock是一个前缀,可以确保“前缀”指令的原子性。

在spinlock / mutex中锁定,而不是lock前缀。 lock前缀仅适用于读 - 修改 - 写指令;没有lock mov [mem], eax来做一个原子未对齐的商店或其他东西。 lock ed总线周期始终是读 - 修改 - 写,正如英特尔在cmpxchg的文档中所记录的那样。因此,lock mov存储也会生成一个加载,如果在内存映射的I / O上使用它,它将具有不同的语义。 (读取可以触发副作用)。

  

我编译并分析了汇编输出...

为什么要将该代码放在main()中,并将未初始化的垃圾从s存储到as?除此之外,main在某些方面很特殊。总是更好地编写一个带有arg(或只影响全局)的函数。 atomic<s>需要是全球性的,而不是一个可能部分优化的本地,如果你想确定你正在看到gcc“真的”做了什么。

#include <atomic>
struct S{ int a,b,c,d,e,f,g,h,i,j,k;  };  // or int a[11]
std::atomic<S> as;
void atomic_struct_store_zero() {
    S s = { 0 };     // initializes all members to zero
    as.store(s);
}

这个compiles to函数调用__atomic_store,传递src和dest指针以及大小。据推测它在某处使用了锁,但锁不是as的一部分。 (sizeof(as) == sizeof(S) == 44)。