【问题标题】: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

标签: c++ multithreading bit-manipulation atomic


【解决方案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> a{0x2216};

    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 中断的内核代码。见stackoverflow.com/questions/19900524/…
  • @chook 你不能先读一读以确定预期的结果吗?
  • @chook 如果您知道操作是什么,您可以确定任何操作、位操作或其他操作的预期结果。您可以使用compare_exchange_weak 将值的任何非原子转换转换为原子转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-15
相关资源
最近更新 更多