原子变量的对齐

时间:2014-11-02 19:19:01

标签: c++ c++11 atomic

当然,为了使典型的现代处理器架构(如x86_64)执行原子加载或存储,需要对齐要读取/写入的数据。

但是这个要求是如何通过C ++ 11 <atomic>变量实际实现/实施的?

假设我有一个支持16字节比较和交换(双字CAS)的架构,因此它可以原子地读/写16字节值,并且我定义了一个16字节类型:

struct double_word
{
    std::uint64_t x;
    std::uint64_t y;
};

现在,假设我将std::atomic<double_word>包含为类的成员字段:

class foo
{
    public:

    std::atomic<double_word> dword;
};

我如何知道foo::dword实际上是在16字节边界上对齐的?我怎么知道对dword.load()的调用实际上原子?

实际上,我最初开始问这个问题是因为我在foo::dword之前添加了另一个数据成员时发生了一件奇怪的事情。我将foo定义为:

class foo
{
    public:

    std::uint64_t x;
    std::atomic<double_word> dword; 
};

当我在foo::dword上实际执行原子加载,并在运行Debian Linux的x86_64机器上使用GCC 4.7.2编译和运行时,它实际上给了我一个分段错误!

完整计划:

#include <atomic>
#include <cstdint>

    struct double_word
    {
        std::uint64_t x;
        std::uint64_t y;
    };

    class foo
    {
        public:

        std::uint64_t x;
        std::atomic<double_word> dword; // <-- not aligned on 16-byte boundary
    };

    int main()
    {
        foo f;
        double_word d = f.dword.load(); // <-- segfaults with GCC 4.7.2 !!
    }

这实际上是f.dword.load()上的段错误。起初我不明白为什么,但后来我意识到dword 在16字节边界上对齐。因此,这导致了许多问题:如果原子变量未对齐并且我们尝试以原子方式加载它,编译器应该怎么做?是不确定的行为?为什么程序只是段错误?

其次,C ++ 11标准对此有何看法?编译器是否应确保double_word在16字节边界上自动对齐?如果是这样,这是否意味着GCC在这里只是错误?如果不是 - 似乎用户需要确保对齐,在这种情况下任何时间我们使用大于一个字节的std::atomic<T>,看起来我们 使用std::aligned_storage来确保它正确对齐,(A)看起来很麻烦,而且(B)是我在实践中或在任何示例/教程中从未真正看到过的东西。

那么,使用C ++ 11 <atomic>的程序员应如何处理这样的对齐问题呢?

2 个答案:

答案 0 :(得分:1)

这是一个GCC错误https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65147 只需添加alignas(16)就可以解决问题。

#include <atomic>
#include <cstdint>

struct double_word
{
    std::uint64_t x;
    std::uint64_t y;
};

class foo
{
    public:

    std::uint64_t x;
    alignas(16) std::atomic<double_word> dword; // <-- not aligned on 16-byte boundary
};

int main()
{
    foo f;
    double_word d = f.dword.load(); // <-- segfaults with GCC 4.7.2 !!
}

答案 1 :(得分:0)

我认为程序员有责任确保dword是16字节对齐。在64位平台上,除非明确指定,否则数据将以64位边界对齐。