Должен ли 64-битный Compare & Swap (CAS) работать на 32-битной машине?(или 64 битная машина?) - PullRequest
1 голос
/ 13 февраля 2012

Итак, я прочитал, что на 32-битной машине можно использовать операцию CAS с выровненными 64-битными блоками. Аналогично, на 64-битной машине можно использовать операцию CAS с выровненными 128-битными блоками.

Я использую 32-битную машину, поэтому я попробовал следующее:

// sizeof(long long) is 8 bytes, so 64 bits
long long y = 12;
long long z = 12;
long long x = 99;
__sync_bool_compare_and_swap(&y, z, x);

и CAS удалось изменить значение y на 99.

Но затем я попытался использовать char array[8]; (размер которого составляет 64 бита) вместо long long. И я делаю:

char full[8] = {'0', '1', '2', '3', '4', '5', '6', '7'}; 
char full2[8] = {'0', '1', '2', '3', '4', '5', '6', '7'};   
char full3[8] = {'5', '8', '9', 'G', 'X', '5', '6', 'U'};
__sync_bool_compare_and_swap(full, full2, full3);  

Но в этом случае CAS завершается неудачно, хотя full и full2 имеют абсолютно одинаковые данные. (Я также проверил, что full и full2, где правильно выровнены)

Таким образом, в первый раз кажется, что CAS может использоваться для 64-битной системы, но во второй раз, кажется, что это невозможно. Есть идеи почему?

EDIT

(Как насчет 64-битных машин?)

Хорошо, проблема была в том, что я использовал char * в своем CAS, и они были только проверены. Таким образом, решение было приведено к long long или uint64_t, которые являются 64-битными значениями.

Но что мне делать с 64-битной машиной, когда мне нужно использовать 128-битное значение? long long по-прежнему 64-битный в 64-битной машине, а uint128_t, кажется, не существует в C. Так к какому типу я должен приводить? double long, кажется, 128-битный в моей 64-битной машине, но при выполнении следующих действий:

  double long y = 32432143243214;
  double long z = 32432143243214;

  int x = __sync_bool_compare_and_swap(&y, z, 1234321990);

Я получаю эту ошибку компиляции error: incompatible type for argument 1 of ‘__sync_bool_compare_and_swap’.

Ответы [ 3 ]

4 голосов
/ 13 февраля 2012

Вы должны передавать значение full2 и full3, а не указатель на него.Кроме того, вы должны заботиться о выравнивании.

__sync_bool_compare_and_swap((long long*)full,*(long long*)full2,*(long long*)full3);

(Конечно, это не переносимо. Если вы хотите переносимости, используйте uint64_t вместо long long)

3 голосов
/ 13 февраля 2012

Похоже, вы забыли разыменовать свои указатели и разыграть.

Я протестировал, и это единственная правильная комбинация:

__sync_bool_compare_and_swap((long long*)full, *(long long *)full2, *(long long *)full3);

Вам нужно разыграть первый параметр или егопоменяет местами только первый символ.

Что касается обработки 128-битной двойной длины, это из gcc 4.1.2 docs .

Определение дано вДокументация Intel допускает использование только типов int, long, long long и их неподписанных аналогов.GCC допускает любой тип целочисленного скаляра или указателя длиной 1, 2, 4 или 8 байтов.

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

2 голосов
/ 13 февраля 2012

Вы передаете char * на __sync_bool_compare_and_swap. Предполагая, что ваши массивы символов (все три из них!) Правильно выровнены по 64 битам (если они распределены так, как вы показываете, они могут не быть - используйте malloc!), Попробуйте привести к (long long *), прежде чем перейти к __sync_bool_compare_and_swap. В противном случае используйте встроенный ассемблер и вызывайте CMPXCHG8B напрямую.

...