Bru*_*ong 3 c++ bit-manipulation atomic bit
我有一些代码,通过首先清除目标 int 中的掩码位,然后将它们或运算到 int 中,将掩码位复制到整数中。
像这样:
bitsToSet = 6
targetInt &= ~(1 << bitsToSet)
targetInt |= desiredBitValue << bitsToSet
Run Code Online (Sandbox Code Playgroud)
问题是它现在需要是线程安全的,并且我需要使操作原子化。我认为使用 std:atomic<int> 只会使每个子操作成为原子操作,而不是整个操作。
如何使整个操作(包括 &= 和 |= 操作)原子化?
例如,如果我有一个函数(或者更好的是宏),SetBits(TARGET, MASK, VALUE)它可以自动将 TARGET 中的 MASKed 位设置为 VALUE,那么它就会为我解决问题。MASK 和 VALUE 已经可以左移。
我当前的非原子代码是
#define SetBits(TARGET, MASK, VALUE) {(TARGET) &= ~((uint64_t)MASK); (TARGET)|=((uint64_t)VALUE);}
Run Code Online (Sandbox Code Playgroud)
您可以使用比较交换循环:
void SetBitsAtomic(std::atomic<int>& target, int mask, int value) {
int original_value = target.load();
int new_value = original_value;
SetBits(new_value, mask, value);
while (!target.compare_exchange_weak(original_value, new_value)) {
// Another thread may have changed target between when we read
// it and when we tried to write to it, so try again with the
// updated value
new_value = original_value;
SetBits(new_value, mask, value);
}
}
Run Code Online (Sandbox Code Playgroud)
这将读取 的原始值target,执行屏蔽操作,然后target仅当自读取以来没有其他线程对其进行修改时,才将修改后的值写回 。如果另一个线程已修改target,则其更新的值将被写入original_value,并且它会继续尝试,直到它设法target先于其他线程进行更新。
请注意,我在这里对load和compare_exchange_weak操作使用了(默认)完全顺序一致性。您可能不需要完全的顺序一致性,但如果没有更多关于您使用它的用途的信息,我无法确切地知道您需要什么。
或者,您可以只使用互斥体:
std::mutex mtx;
void SetBitsAtomic(int& target, int mask, int value) {
std::lock_guard lock{mtx};
SetBits(target, mask, value);
}
Run Code Online (Sandbox Code Playgroud)
这可能比无锁compare_exchange_weak版本的性能要差,但这实际上取决于它的用途。它当然更简单、更容易推理,在您的情况下,这可能比原始性能更重要。