保证原子性的单比特操作
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
将值的任何非原子转换转换为原子转换。以上是关于保证原子性的单比特操作的主要内容,如果未能解决你的问题,请参考以下文章