What is the cheapest technique to update a single bit (from a std::bitset
) atomically? I don't think x86 BTR
is atomic.
I'm wondering if I would have to read the nearest byte and then use a CAS?
If LOCK
+ BTR
is the speediest solution, I would gladly accept an inlined, x86-64 assembly answer.
BTS/BTR are not atomic by default, but they can be with the LOCK prefix.
Here is my implementation of atomic bit set and atomic bit reset, that works on both Intel 64 bits and 32 bits platform (works with both MSVC, gcc and probably clang).
Implementation for ARM is also available from: 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With