16-разрядное чтение Atomic на процессорах x64 - PullRequest
11 голосов
/ 15 марта 2012

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

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

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

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

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

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

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

Ответы [ 2 ]

9 голосов
/ 15 марта 2012
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
1 голос
/ 15 марта 2012

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

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

...