std ::原子trivially可复制的结构 [英] std::atomic trivially copyable structs

查看:208
本文介绍了std ::原子trivially可复制的结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++参考说: http://en.cppreference.com/w/cpp / atomic / atomic


std :: atomic可以用任何TriviallyCopyable类型T实例化

然而下面的例子在g ++ 6.2.0下无效

  #include< atomic> 
#include< functional>

struct Test11 {
int x;
};
struct Test12 {
char x;
};
struct Test13 {
long x;
};
struct Test2 {
char x;
int y;
};
struct Test3 {
int y;
long x;
};

模板< typename T,typename ... ARGS>
void test(ARGS&& ... args){
static_assert(std :: is_trivially_copyable< T> :: value);

std :: atomic< T>一个;
a.store(T {std :: forward< ARGS>(args)...});


int main(){
test< Test11>(1);
test< Test12>('\1');
test< Test13>(1L);
test< Test2>('\1',2);
test< Test3>(1,2L);
返回0;
}

编译: g ++ - 6 -std = c + +14 -latomic test.cpp


/tmp/cchademz.o:在函数 std :: atomic< Test3> :: store(Test3,std :: memory_order)
test.cpp :(。text._ZNSt6atomicI5Test3E5storeES0_St12memory_order [_ZNSt6atomicI5Test3E5storeES0_St12memory_order] + 0x3e):undefined reference to __ atomic_store_16
collect2:错误:ld返回1退出状态

g ++ - 6 --version


g ++(Ubuntu 6.2.0-7ubuntu11) 6.2.0 20161018

特别是我不明白为什么 Test2 code> Test3 不会。



有什么想法?

编辑:添加-latomic标志和g ++版本

解决方案

正如@TartanLlama在其现已删除 answer ,你需要链接 libatomic

  g ++  -  6 -std = c ++ 14 test.cpp -latomic 

您需要在编辑行末尾添加 -latomic 。如果在 test.cpp 之前放置 -latomic (例如),则某些编译器(链接器) > g ++ 在Coliru上),但有些不会(请参阅为什么库链接的顺序有时会导致GCC错误?)。

< 免责声明:我不是联系方面的专家,所以我无法详细解释为什么它在 -latomic 平台,而不是其他人(我猜连接器是不同的,但...)。




至于为什么你的代码编译,如果你删除 Test3 ,这是依赖于编译器和体系结构。如果您使用 -O2 g ++ 6.2 godbolt 上查看生成的ASM, :

  sub rsp,24 
movabs rax,8589934593
mov ecx,5
mov DWORD PTR [rsp],1
mov rdi,rsp
mov esi,1
mov edx,2
mfence
mov BYTE PTR [rsp],1
mfence
mov QWORD PTR [rsp],1
mfence
mov QWORD PTR [rsp],rax
mfence
call __atomic_store_16

您会发现,对于少于8个字节的结构( Test1X Test2 ),编译器可以使用 mov QWORD 指令(在当今体系结构中qword通常为8个字节),但它不能生成单个指令来处理尺寸严格大于8的情况( sizeof(Test3)通常为16)。



基本上,可能有专门的 std :: atomic< T> (或一些 g ++ 1 T>时,c $ c> std :: atomic< T> 是small,而small的定义可能是与架构相关的。

免责声明:我不是关于< atomic> 的专家,所以这主要来自对godbolt生成的ASM和 g ++ 和 clang 在Coliru上。



1 clang 有一个 __ atomic_store_8 过程和一个 __ atomic_store 过程,并且没有 -latomic 它不会编译为 Test2 Test3 。然而,即使 sizeof(Test13)是8,它仍然可以编译 Test13 ,所以它不会使用 __attribute_store_8 用于某些结构。 icc 具有完全不同的行为,并且不会生成任何调用(无法在Coliru上测试,但您可以查看它在godbolt上)。

C++ reference says: http://en.cppreference.com/w/cpp/atomic/atomic

std::atomic may be instantiated with any TriviallyCopyable type T

However following example does not work under g++ 6.2.0

#include <atomic>
#include <functional>

struct Test11 {
    int x;
};
struct Test12 {
    char x;
};
struct Test13 {
    long x;
};
struct Test2 {
    char x;
    int y;
};
struct Test3 {
    int y;
    long x;
};

template<typename T, typename... ARGS>
void test(ARGS&& ... args) {
    static_assert(std::is_trivially_copyable<T>::value);

    std::atomic<T> a;
    a.store(T{std::forward<ARGS>(args)...});
}

int main() {
    test<Test11>(1);
    test<Test12>('\1');
    test<Test13>(1L);
    test<Test2>('\1',2);
    test<Test3>(1,2L);
    return 0;
}

Compile: g++-6 -std=c++14 -latomic test.cpp

/tmp/cchademz.o: In function std::atomic<Test3>::store(Test3, std::memory_order): test.cpp:(.text._ZNSt6atomicI5Test3E5storeES0_St12memory_order[_ZNSt6atomicI5Test3E5storeES0_St12memory_order]+0x3e): undefined reference to __atomic_store_16 collect2: error: ld returned 1 exit status

g++-6 --version

g++ (Ubuntu 6.2.0-7ubuntu11) 6.2.0 20161018

Especially I do not understand why Test2 works but Test3 does not.

Any ideas?

EDIT: added -latomic flag and g++ version

解决方案

As mentioned by @TartanLlama in its now-deleted answer, you need to link against libatomic:

g++-6 -std=c++14 test.cpp -latomic

You need to add -latomic at the end of the compilation line. Some compilers (linkers) may work correctly if you put -latomic before test.cpp (e.g. g++ on Coliru), but some won't (see Why does the order in which libraries are linked sometimes cause errors in GCC?).

Disclaimer: I am not an expert in linkage, so I cannot provide a detailed explanation as to why it works with -latomic before on some platform and not on other (I am guessing the linkers are different, but... ).


As to why your code compiles if you remove Test3, this is compiler and architecture dependent. If you look at the generated ASM with -O2 and g++6.2 on godbolt:

sub     rsp, 24
movabs  rax, 8589934593
mov     ecx, 5
mov     DWORD PTR [rsp], 1
mov     rdi, rsp
mov     esi, 1
mov     edx, 2
mfence
mov     BYTE PTR [rsp], 1
mfence
mov     QWORD PTR [rsp], 1
mfence
mov     QWORD PTR [rsp], rax
mfence
call    __atomic_store_16

You see that for structure that takes less than 8 bytes (Test1X, Test2), the compiler can use the mov QWORD instruction (a qword is usually 8 bytes long on nowadays architectures), but it cannot generate a single instruction to handle the cases where the size is strictly greater than 8 (sizeof(Test3) will usually be 16).

Basically, there is probably a specialization of std::atomic<T> (or of some operations of std::atomic<T>) in g++1 when T is "small", and the definition of "small" is probably architecture dependent.

Disclaimer: Again, I am not an expert regarding <atomic> so this is mainly from experiments regarding generated ASM on godbolt and behaviour of g++ and clang on Coliru.

1 clang has a __atomic_store_8 procedure and a __atomic_store procedure, and without -latomic it will not compile for Test2 and Test3. However it manages to compile Test13 even if sizeof(Test13) is 8 so it does not use __atomic_store_8 for some structures. icc has a completely different behavior and does not generate any call (cannot test on Coliru, but you can look it up on godbolt).

这篇关于std ::原子trivially可复制的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆