std ::原子trivially可复制的结构 [英] std::atomic trivially copyable structs
问题描述
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
您需要在编辑行末尾添加 至于为什么你的代码编译,如果你删除 您会发现,对于少于8个字节的结构( 基本上,可能有专门的 免责声明:我不是关于 1 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 Compile: /tmp/cchademz.o: In function g++ (Ubuntu 6.2.0-7ubuntu11) 6.2.0 20161018 Especially I do not understand why Any ideas? EDIT: added -latomic flag and g++ version As mentioned by @TartanLlama in its now-deleted answer, you need to link against You need to add Disclaimer: I am not an expert in linkage, so I cannot provide a detailed explanation as to why it works with As to why your code compiles if you remove You see that for structure that takes less than 8 bytes ( Basically, there is probably a specialization of Disclaimer: Again, I am not an expert regarding 1 这篇关于std ::原子trivially可复制的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! -latomic
。如果在 test.cpp
之前放置 -latomic
(例如),则某些编译器(链接器) > g ++
在Coliru上),但有些不会(请参阅为什么库链接的顺序有时会导致GCC错误?)。
< 免责声明:我不是联系方面的专家,所以我无法详细解释为什么它在
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
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上。
clang
有一个 __ atomic_store_8
过程和一个 __ atomic_store
过程,并且没有 -latomic
它不会编译为 Test2
和 Test3
。然而,即使 sizeof(Test13)
是8,它仍然可以编译 Test13
,所以它不会使用 __attribute_store_8
用于某些结构。 icc
具有完全不同的行为,并且不会生成任何调用
(无法在Coliru上测试,但您可以查看它在godbolt上)。
#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;
}
g++-6 -std=c++14 -latomic test.cpp
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 statusg++-6 --version
Test2
works but Test3
does not.libatomic
:g++-6 -std=c++14 test.cpp -latomic
-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?).-latomic
before on some platform and not on other (I am guessing the linkers are different, but... ).
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
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).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.<atomic>
so this is mainly from experiments regarding generated ASM on godbolt and behaviour of g++
and clang
on Coliru.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).