LINUX.ORG.RU

std::atomic — откуда он знает по выровненому адресу он лежит или нет?

 


1

2

На x86 MOV атомарен для слова по выровненному адресу. Если не по выровненому, то надо LOCK MOV. Или я гоню? Если не гоню, то как будет выкручиваться std::atomic<uint32_t>, созданный по кривому невыровненному адресу?

А в чем собственно проблема? this это указатель. Что мешает проверить его младшие биты?

KivApple ★★★★★
()

откуда он знает по выровненому адресу он лежит или нет?

Ему стандарт гарантирует. /thread

anonymous
()

У него внутре alignas.

anonymous
()
Ответ на: комментарий от hlamotron
  template<typename _ITp>
    struct __atomic_base
    {
    private:
      typedef _ITp __int_type;

      static constexpr int _S_alignment =
        sizeof(_ITp) > alignof(_ITp) ? sizeof(_ITp) : alignof(_ITp);

      alignas(_S_alignment) __int_type _M_i; // <<<<<<<

//...
sjinks ★★★
()
Ответ на: комментарий от sjinks

Вот есть адрес N. Он может быть выровненный или нет. Как узнать, сколько байтов памяти я сожру, желая положить туда std::atomic<uint64_t>? Ведь из-за alignas размер должен меняться, а как эту зависимость уловить через sizeof()?

char *mem = 0x12345;
auto *p = ::new(mem) std::atomic<uint64_t>;
// сколько шагнуть от p вперёд, чтобы не наехать на объект?
hlamotron
() автор топика

Насколько я понимаю, не выровненный atomic, так же как и не выровненный int - это undefined behavior (особо заметно на ARM). Но, даже на x86 работа с не выровненными данными может привести к ошибке http://pzemtsov.github.io/2016/11/06/bug-story-alignment-on-x86.html

Так что, если ты создаешь atomic на стеке или через new, то он будет правильно выровнен, а если делаешь cast или placement new, то получишь неопределенное поведение.

chimera19
()
Ответ на: комментарий от hlamotron

Ведь из-за alignas размер должен меняться

std::atomic<uint64_t> грубо говоря будет alignas(8) uint64_t и sizeof(alignas(8) uint64_t) == sizeof(uint64_t). Для статических объектов выравнивание контролируется компилятором, для динамических new выравнивает данные по alignof(std::max_align_t).

Если же размещать данные динамически через placement new по невыравненному адресу, будет UB, как я понимаю.

$ cat test.cpp
#include <iostream>
#include <new>
#include <emmintrin.h>

int main()
{
    char c[sizeof(__m128i)+1];
    __m128i* t = new(&c[1]) __m128i;
    __m128i  u = _mm_set1_epi8(0);
    std::cout << "Before _mm_store_si128 " << t << std::endl;
    _mm_store_si128(t, u);
    std::cout << "After _mm_store_si128" << std::endl;
    return 0;
}

$ g++ test.cpp -O0 -o test && ./test
Before _mm_store_si128 0x7ffde0aaf621
Помилка адресування (збережено знімок оперативної пам’яті)

При -O2 компилятор догадается, что адрес невыравнен и будет использовать movups; с -O0 будет movdqa и падение.

sjinks ★★★
()

На x86 MOV атомарен для слова по выровненному адресу. Если не по выровненому, то надо LOCK MOV.

LOCK (если ты про префикс) в таких случаях нужен всегда

anonymous
()
Ответ на: комментарий от anonymous

Почему всегда? Взгляд на ассемблерный код std::atomic<uint32_t>.store(0), например, показывает, что там стоит просто MOV (а за ним идёт инструкция MFENCE).

hlamotron
() автор топика
Ответ на: комментарий от hlamotron

А placement new std::atomic<uint64_t> по выровненному адресу гарантированно безопасен?

«e.g. some platforms only provide atomic operations on words, so std::atomic<uint8_t> will use a full machine word where plain uint8_t can just use a byte.»

Отсюда http://stackoverflow.com/questions/8749038/how-to-use-stdatomic-efficiently

Автор Anthony Williams - считай что бог в этой теме.

Еще одна особенность - атомарная переменная может быть атомарной, но не lockfree. В этом случае компилятор реализует атомарность через блокировку. Думаю, в таком случае к переменной будет добавлен еще и атомарный флаг для блокировки. Кстати, большинство x86 процессоров умеют атомарно (и lockfree) реализовывать работу с двумя uint64_t, т.е. с блоком длинной 16 байт (разумеется выровненных).

Так что ответ на твой вопрос: «обычно безопасен, но бывают исключения».

P.S. Ты уже создавал похожий топик C++ std::atomic<uint64_t> в шареной памяти., зачем этот дубль?

chimera19
()
Ответ на: комментарий от chimera19

Это ты щас не ответил на вопрос о безопасности std::atomic<uint64_t> по выровненному адресу, а освятил другой вопрос - uint8_t и про лок-фри.

hlamotron
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.