Почему std::atomic<double> не реализован при компиляции с помощью clang?
Рассмотрим следующий фрагмент кода:
#include <atomic>
int main(void) {
std::atomic<double> aDouble;
aDouble = 6.0;
}
G ++ компилирует это просто отлично, в то время как clang++ производит следующее:
clang++ -std=c++11 Main.cpp
/tmp/Main-d4f0fc.o: In function `std::atomic<double>::store(double, std::memory_order)':
Main.cpp:(.text._ZNSt6atomicIdE5storeEdSt12memory_order[_ZNSt6atomicIdE5storeEdSt12memory_order]+0x31): undefined reference to `__atomic_store_8'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Разве они не ссылаются на одну и ту же стандартную библиотеку?
1 ответ
Если clang++ -stdlib=libstdc++
не решает вашу проблему, свяжитесь с -latomic
для реализации этих функций.
Попытайтесь заставить свой компилятор встроить 8-байтовые и более узкие атомы, потому что функции библиотеки имеют потенциально большие недостатки.
Помните, что библиотечные функции не поддерживают более слабый порядок памяти memory_order_seq_cst
поэтому они всегда используют mfence
на x86, даже если источник использовал relaxed
,
32-разрядная версия x86 __atomic_store_8
еще хуже: он использует lock cmpxchg8b
вместо SSE или x87 8-байтовое хранилище. Это заставляет его работать, даже если он не выровнен, но при значительном снижении производительности. Он также имеет два избыточных lock or [esp], 0
инструкции как дополнительные барьеры для загрузки своих аргументов из стека. (Я смотрю на /usr/lib32/libatomic.so.1.2.0
из gcc7.1.1 в Arch Linux.)
По иронии судьбы, текущий gcc -m32 (в режиме C11, а не C++11) занижен atomic_llong
внутри структуры, но внутри строк movq xmm
загружает / хранит, так что это на самом деле не атомарно. ( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65146)
Текущий лязг -m32 выравнивает atomic_llong
до 8 байт даже внутри структур (в отличие от обычных long long
, который i386 System V ABI выравнивает только до 4B). Ирония в том, что clang генерирует вызовы библиотечных функций, которые используют lock cmpxchg8b
( https://bugs.llvm.org/show_bug.cgi?id=33109), поэтому он на самом деле атомарен даже при разделении строк кэша. ( Почему целочисленное присваивание для естественно выровненной переменной атомарно в x86?).
Таким образом, clang безопасен, даже если какой-то gcc-скомпилированный код передает ему указатель на выровненный _Atomic long long
, Но он не согласен с gcc по поводу разметки структуры, так что это может помочь, только если он получает указатель на атомарную переменную напрямую, а не на содержащую структуру.
Связанный: атомная двойная с плавающей точкой или SSE/AVX векторная загрузка / сохранение на x86_64