std::atomic 简单可复制的结构
std::atomic trivially copyable structs
C++ 参考说:http://en.cppreference.com/w/cpp/atomic/atomic
std::atomic may be instantiated with any TriviallyCopyable type 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;
};
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>('');
test<Test13>(1L);
test<Test2>('',2);
test<Test3>(1,2L);
return 0;
}
编译: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
特别是我不明白为什么 Test2
有效而 Test3
无效。
有什么想法吗?
编辑: 添加了 -latomic 标志和 g++ 版本
正如@TartanLlama 在现已删除的 answer 中提到的,您需要 link 反对 libatomic
:
g++-6 -std=c++14 test.cpp -latomic
您需要在编译行的末尾添加-latomic
。如果您将 -latomic
放在 test.cpp
之前(例如 Coliru 上的 g++
),某些编译器(link 人)可能会正常工作,但有些则不会(请参阅 Why does the order in which libraries are linked sometimes cause errors in GCC? ).
免责声明:我不是link年龄方面的专家,所以我无法详细解释为什么它适用于-latomic
某些平台而不是其他平台(我猜 link 用户不同,但是...)。
至于为什么删除 Test3
后代码可以编译,这取决于编译器和体系结构。如果您在 godbolt:
上使用 -O2
和 g++6.2
查看生成的 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)。
基本上,当 T
是 "small","small" 的定义可能与体系结构有关。
免责声明: 同样,我不是 <atomic>
方面的专家,所以这主要来自关于在 godbolt 上生成的 ASM 和 g++
的行为的实验,以及clang
在 Coliru 上。
1 clang
有一个 __atomic_store_8
过程和一个 __atomic_store
过程,没有 -latomic
它不会为 Test2
和 Test3
编译。然而它设法编译 Test13
即使 sizeof(Test13)
是 8 所以它不对某些结构使用 __atomic_store_8
。 icc
具有完全不同的行为,不会生成任何 call
(无法在 Coliru 上测试,但您可以在 godbolt 上查找)。
C++ 参考说:http://en.cppreference.com/w/cpp/atomic/atomic
std::atomic may be instantiated with any TriviallyCopyable type 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;
};
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>('');
test<Test13>(1L);
test<Test2>('',2);
test<Test3>(1,2L);
return 0;
}
编译: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
特别是我不明白为什么 Test2
有效而 Test3
无效。
有什么想法吗?
编辑: 添加了 -latomic 标志和 g++ 版本
正如@TartanLlama 在现已删除的 answer 中提到的,您需要 link 反对 libatomic
:
g++-6 -std=c++14 test.cpp -latomic
您需要在编译行的末尾添加-latomic
。如果您将 -latomic
放在 test.cpp
之前(例如 Coliru 上的 g++
),某些编译器(link 人)可能会正常工作,但有些则不会(请参阅 Why does the order in which libraries are linked sometimes cause errors in GCC? ).
免责声明:我不是link年龄方面的专家,所以我无法详细解释为什么它适用于-latomic
某些平台而不是其他平台(我猜 link 用户不同,但是...)。
至于为什么删除 Test3
后代码可以编译,这取决于编译器和体系结构。如果您在 godbolt:
-O2
和 g++6.2
查看生成的 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)。
基本上,当 T
是 "small","small" 的定义可能与体系结构有关。
免责声明: 同样,我不是 <atomic>
方面的专家,所以这主要来自关于在 godbolt 上生成的 ASM 和 g++
的行为的实验,以及clang
在 Coliru 上。
1 clang
有一个 __atomic_store_8
过程和一个 __atomic_store
过程,没有 -latomic
它不会为 Test2
和 Test3
编译。然而它设法编译 Test13
即使 sizeof(Test13)
是 8 所以它不对某些结构使用 __atomic_store_8
。 icc
具有完全不同的行为,不会生成任何 call
(无法在 Coliru 上测试,但您可以在 godbolt 上查找)。