保证原子性的单比特操作

Posted

技术标签:

【中文标题】保证原子性的单比特操作【英文标题】:Single bit manipulations with guaranteed atomicity 【发布时间】:2017-06-26 00:09:19 【问题描述】:

有没有办法在 c++ 中将单个位设置、清除、测试和翻转作为原子操作?例如“compare_and_swap”的按位变体。

【问题讨论】:

std::atomic_bool? 没有“C/C++”。选择一个 您使用的是什么架构?如果给定的架构不支持位级原子操作,那么语言/编译器就不会神奇地实现它。 @Tony K 架构是 x86-64 使用 c++ 时检查 std::bitset 【参考方案1】:

原子操作位需要compare_exchange RMW 以避免触及atomic 变量中的其他位。 测试一点不是修改操作,因此load() 就足够了。

你将不得不添加范围错误检查

template<typename T, typename OP>
T manipulate_bit(std::atomic<T> &a, unsigned n, OP bit_op)

    static_assert(std::is_integral<T>::value, "atomic type not integral");

    T val = a.load();
    while (!a.compare_exchange_weak(val, bit_op(val, n)));

    return val;


auto set_bit = [](auto val, unsigned n)  return val | (1 << n); ;
auto clr_bit = [](auto val, unsigned n)  return val & ~(1 << n); ;
auto tgl_bit = [](auto val, unsigned n)  return val ^ (1 << n); ;


int main()

    std::atomic<int> a0x2216;

    manipulate_bit(a, 3, set_bit);  // set bit 3

    manipulate_bit(a, 7, tgl_bit);  // toggle bit 7

    manipulate_bit(a, 13, clr_bit);  // clear bit 13

    bool isset = (a.load() >> 5) & 1;  // testing bit 5

【讨论】:

好;我会return val;,因为知道你从什么过渡通常很有用。 同意;它实际上更接近原子操作遵循的设计约定 我是否遗漏了什么,或者您不应该在循环中更新 val 吗?否则,您将陷入死锁,直到 a 具有其旧值。 @morty 如果compare_exchange_weak 返回 false,它将使用当前值更新其第一个参数。因此,第一个参数 (val) 必须是左值引用。 @LWimsey:是的。谢谢。我真的希望 C++ 需要一个关键字来突出它是一个左值引用并且它可能会被修改。【参考方案2】:

在整数中翻转一位只是比较和交换操作。您使用它来测试和翻转一点不会改变任何东西。所以一个简单的compare_exchange_weak 循环就可以做到这一点。

【讨论】:

在 compare_exchange_weak 中假定您知道预期的结果。这不是位操作的情况。 请注意,C/C++“原子”与不可中断意义上的原子操作不同,它只是保证一定程度的线程安全。例如 stdatomic.h 不适用于可被 ISR 中断的内核代码。见***.com/questions/19900524/… @chook 你不能先读一读以确定预期的结果吗? @chook 如果您知道操作是什么,您可以确定任何操作、位操作或其他操作的预期结果。您可以使用compare_exchange_weak 将值的任何非原子转换转换为原子转换。

以上是关于保证原子性的单比特操作的主要内容,如果未能解决你的问题,请参考以下文章

为什么volatile能保证有序性不能保证原子性

为什么volatile能保证有序性不能保证原子性

Redis 的事务到底是不是原子性的

2. 原子性 Atomic

CAS怎么保证原子性的

CAS怎么保证原子性的