Атомный 16-байтовый режим считывается на процессорах x64

Мне нужно читать/писать 16 байт атомарно. Я пишу только с использованием cmpxchg16, который доступен на всех процессорах x64, за исключением того, что я думаю для одного неясного AMD.

Теперь вопрос заключается в выровненных 16 байтовых значениях, только когда-либо измененных с использованием cmpxchg16 (который действует как полный барьер памяти), возможно ли когда-либо прочитать 16-байтовое местоположение, что половина старых данных и половина новых данных?

Пока я читаю инструкцию SSE (поэтому поток не может быть прерван в середине чтения), я думаю, что это невозможно (даже в многопроцессорных системах numa) для чтения, чтобы увидеть несогласованные данные. Я думаю, что он должен быть атомарным.

Я исхожу из предположения, что при выполнении cmpxchg16 он изменяет 16 байтов атомарно, а не записывая два 8-байтовых блока с возможностью для других потоков читать между ними (честно говоря, я не вижу, как это могло бы быть если он не был атомарным.)

Я прав? Если я ошибаюсь, есть ли способ сделать атомный 16-байтовый текст без использования блокировки?

Примечание. Здесь есть пара вопросов но они не имеют отношения к случаю, когда записи выполняются только с cmpxchg16, поэтому я считаю, что это отдельный, неотвеченный вопрос.

Изменить: На самом деле, я думаю, что мои рассуждения были ошибочными. Инструкция загрузки SSE может выполняться как два 64-битных чтения, и может быть возможно, чтобы cmpxchg16 выполнялся между двумя чтениями другим процессором.

Ответ 1

typedef struct
{
  unsigned __int128 value;
} __attribute__ ((aligned (16))) atomic_uint128;

unsigned __int128
atomic_read_uint128 (atomic_uint128 *src)
{
  unsigned __int128 result;
  asm volatile ("xor %%rax, %%rax;"
                "xor %%rbx, %%rbx;"
                "xor %%rcx, %%rcx;"
                "xor %%rdx, %%rdx;"
                "lock cmpxchg16b %1" : "=A"(result) : "m"(*src) : "rbx", "rcx");
  return result;
}

Это должно сделать трюк. Typedef обеспечивает правильное выравнивание. Для cmpxchg16b нужны данные, которые должны быть выровнены по 16-байтовой границе.

cmpxchg16b будет тестировать, если *src содержит нуль и записывает нуль, если это так (nop). В любом случае правильное значение будет стоять в RAX: впоследствии RDX.

Приведенный выше код оценивается примерно так же, как

push   %rbx
xor    %rax,%rax
xor    %rbx,%rbx
xor    %rcx,%rcx
xor    %rdx,%rdx
lock cmpxchg16b (%rdi)
pop    %rbx
retq

Ответ 2

В соответствии со ссылками http://siyobik.info/main/reference/instruction/CMPXCHG8B%2FCMPXCHG16B CMPXCHG16 по умолчанию не является атомарным, но может быть сделан атомом, используя LOCK http://siyobik.info/main/reference/instruction/LOCK

Это означает, что по умолчанию данные могут быть изменены на этапах чтения и записи. Блокировка делает как чтение, так и запись атомом.