2016-11-22 1 views
1

Структура C++ ссылки говорит: http://en.cppreference.com/w/cpp/atomic/atomicстанда :: атомная тривиальный Copyable

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

Однако следующий пример не работает под г ++ 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

Особенно я не понимаю, почему Test2 работает, но Test3 нет.

Любые идеи?

EDIT: добавил -latomic флаг и г ++ версии

+2

Вы пытались добавить '-latomic' в конце строки компиляции случайно? Код компилируется на coliru с помощью '-latomic' (g ++ 6.2): ​​http://coliru.stacked-crooked.com/a/fd421bd3d1715897 – Holt

+0

Вместо этого вы можете включить ? –

+0

переезд '-латомный' до конца работал. Но почему? – WaeCo

ответ

4

Как отметил @TartanLlama в его теперь удалены answer, необходимо связать с libatomic:

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

Вам нужно добавить -latomic в конце строки компиляции. Некоторые компиляторы (компоновщики) могут работать правильно, если вы положили -latomic до test.cpp (например, g++ на Coliru), но некоторые не будут (см. Why does the order in which libraries are linked sometimes cause errors in GCC?).

Отказ от ответственности: Я не эксперт в области связи, поэтому я не могу подробно объяснить, почему он работает с -latomic раньше на какой-то платформе, а не на другой (я предполагаю, что линкеры разные, но .. .).


Как, почему ваш код компилируется, если вы удалите Test3, это компилятор и зависит от архитектуры. Если вы посмотрите на сгенерированный ASM с -O2 и g++6.2 на 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 

Вы видите, что для структуры, которая занимает меньше 8 байт (Test1X, Test2), компилятор может использовать mov QWORD инструкцию (а QWORD обычно 8 байтов на современных архитектурах), но он не может создать одну инструкцию для обработки случаев, когда размер строго больше 8 (sizeof(Test3) обычно будет 16).

В принципе, есть, вероятно, специализации std::atomic<T> (или некоторые операции std::atomic<T>) в g++ , когда T «мало», и определение «малые», вероятно, зависит от архитектуры.

Отказ от ответственности: Опять же, я не являюсь экспертом в отношении <atomic> так это в основном из экспериментов, касающихся генерируемый ASM на godbolt и поведении g++ и clang на Coliru.

clang имеет __atomic_store_8 процедуру и __atomic_store процедуру, и без -latomic он не будет составлять для Test2 и Test3. Однако ему удается скомпилировать , даже если sizeof(Test13) равно 8, поэтому для некоторых структур он не использует __atomic_store_8. icc имеет совершенно другое поведение и не генерирует call (не может протестировать на Coliru, но вы можете посмотреть его на godbolt).