Без блокировки только с 8-байтовым CAS? C ++

0

Я использую 64-разрядную систему x86, ограниченную максимум 8 байтами для операций сравнения и свопинга. Поскольку указатели являются 8-байтами, и мне нужен счетчик, чтобы избежать проблемы с ABA, возможно ли изменить верхние 16 бит указателя, которые не используются для хранения счетчика?

pointer_as_dec = reinterpret_cast<uintptr_t>(&node); // Node address
pointer_as_dec+(1LLU<<48); // Initialize the counter in one of the upper bits

Можно ли использовать функцию __sync_bool_compare_and_swap для хранения измененного адреса указателя?

Теги:
c++11
atomic
thread-safety

1 ответ

2
Лучший ответ

Ну, это не гарантируется работать в соответствии с любым стандартом - единственное, что вам действительно разрешено делать с приведением указателя в int, - это вернуть его обратно в указатель без изменений. Но практически он будет работать на любой платформе x86_64 и практически любой другой текущей платформе. И, очевидно, вы не ожидали, что gcc-специфичный, x86_64-специфичный код будет переносимым. Итак, здесь нет проблем.

Кроме того, uintptr_t не является одним из поддерживаемых типов для gcc-функций, но он полностью совместим с unsigned long long int. (Если вы беспокоитесь об этом, вы всегда можете добавить второй бросок...) Таким образом, здесь нет проблем.

Между тем, __sync_bool_compare_and_swap не заботится о том, чтобы вы контрабандировали указатель в этом uintptr_t; насколько это касается, это просто неподписанное 64-битное целое число. Итак, здесь нет проблем.

Вы действительно можете быть уверены, что первые 16 бит всегда пусты? В x86_64 linux они предназначены для вашей обычной пользовательской памяти. Возможно, они не предназначены для указателей на память ядра или аппаратное обеспечение с отображением памяти, и они могут быть не в других системах x86_64, но в противном случае они будут всего 1 с. И, как указывает Брендан, это гарантируется для всего, что работает на оборудовании x86_64 без 128-разрядного CAS. * Итак, если вам нужно указать на такую память или порт на такие системы, просто используйте 15 бит вместо 16. (И даже если это были неверны, предполагая, что вы указываете, скажем, на объекты с 64-битным выравниванием, у вас также есть 6 свободных бит на другом конце указателя, которые вы могли бы использовать вместо этого.) Таким образом, нет проблема здесь тоже.


* За исключением маловероятного события, которое AMD или Intel или кто-то другой решает изменить размер виртуального адреса, а также решает отнять 128-битный CAS...

  • 0
    Спасибо за ваш ответ, это полезно. Поскольку _sync_bool_cas принимает указатель на ячейку памяти в качестве первого аргумента, как бы я передавал число, хранящееся в uintptr_t (точнее, в uint64_t после того, как я это произвел), а не указатель на саму переменную uintptr_t?
  • 0
    @ user3217789: Вы не можете использовать munged-up-disguised-pointer в uintptr_t в качестве указателя , вы можете использовать его только в качестве значения . Независимо от структуры у вас есть , что ссылки какой - то объект , который должен быть CAS'd, вы храните потеряются указатели там, вместо реальных указателей. Затем вы CAS их, используя адрес прямо в структуре. И вы должны снять кусочки, чтобы разорвать их.
Показать ещё 9 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню