Какой самый дешевый метод обновления одного бита (от std::bitset
) атомно? Я не думаю, что x86 BTR
атомно.
Мне интересно, если бы я должен был прочитать ближайший байт, а затем использовать CAS?
Если LOCK
+ BTR
является самое быстрое решение, я бы с радостью принял встроенный ответ на сборку x86-64.
BTS / BTR не являются атомарными по умолчанию, но они могут быть с префиксом LOCK.
Вот моя реализация набора атомарных битов и сброса атомных битов, которая работает как на 64-битной, так и на 32-битной платформе Intel (работает как с MSVC, gcc и, возможно, clang).
Реализация для ARM также доступна от:
http://alice.loria.fr/software/geogram/doc/html/atomics_8h_source.html
/**
* \brief Atomically tests and sets a bit (INTEL only)
* \details Sets bit \p bit of *\p ptr and returns its previous value.
* The function is atomic and acts as a read-write memory barrier.
* \param[in] ptr a pointer to an unsigned integer
* \param[in] bit index of the bit to set in *\p ptr
* \return the previous value of bit \p bit
*/
inline char atomic_bittestandset_x86(volatile unsigned int* ptr, unsigned int bit) {
char out;
#if defined(__x86_64)
__asm__ __volatile__ (
"lock; bts %2,%1\n" // set carry flag if bit %2 (bit) of %1 (ptr) is set
// then set bit %2 of %1
"sbb %0,%0\n" // set %0 (out) if carry flag is set
: "=r" (out), "=m" (*ptr)
: "Ir" (bit)
: "memory");
#else
__asm__ __volatile__ (
"lock; bts %2,%1\n" // set carry flag if bit %2 (bit) of %1 (ptr) is set
// then set bit %2 of %1
"sbb %0,%0\n" // set %0 (out) if carry flag is set
: "=q" (out), "=m" (*ptr)
: "Ir" (bit)
: "memory");
#endif
return out;
}
/**
* \brief Atomically tests and resets a bit (INTEL only)
* \details Resets bit \p bit of *\p ptr and returns its previous value.
* The function is atomic and acts as a read-write memory barrier
* \param[in] ptr a pointer to an unsigned integer
* \param[in] bit index of the bit to reset in \p ptr
* \return the previous value of bit \p bit
*/
inline char atomic_bittestandreset_x86(volatile unsigned int* ptr, unsigned int bit) {
char out;
#if defined(__x86_64)
__asm__ __volatile__ (
"lock; btr %2,%1\n" // set carry flag if bit %2 (bit) of %1 (ptr) is set
// then reset bit %2 of %1
"sbb %0,%0\n" // set %0 (out) if carry flag is set
: "=r" (out), "=m" (*ptr)
: "Ir" (bit)
: "memory");
#else
__asm__ __volatile__ (
"lock; btr %2,%1\n" // set carry flag if bit %2 (bit) of %1 (ptr) is set
// then reset bit %2 of %1
"sbb %0,%0\n" // set %0 (out) if carry flag is set
: "=q" (out), "=m" (*ptr)
: "Ir" (bit)
: "memory");
#endif
return out;
}