朴素布尔否定
std::atomic_bool b;
b = !b;似乎不是原子的。我怀疑这是因为operator!触发了对普通bool的转换。一个人将如何原子地执行等价的否定?下面的代码说明天真的否定不是原子的:
#include <thread>
#include <vector>
#include <atomic>
#include <iostream>
typedef std::atomic_bool Bool;
void flipAHundredThousandTimes(Bool& foo) {
for (size_t i = 0; i < 100000; ++i) {
foo = !foo;
}
}
// Launch nThreads std::threads. Each thread calls flipAHundredThousandTimes
// on the same boolean
void launchThreads(Bool& foo, size_t nThreads) {
std::vector<std::thread> threads;
for (size_t i = 0; i < nThreads; ++i) {
threads.emplace_back(flipAHundredThousandTimes, std::ref(foo));
}
for (auto& thread : threads) thread.join();
}
int main() {
std::cout << std::boolalpha;
Bool foo{true};
// launch and join 10 threads, 20 times.
for (int i = 0; i < 20; ++i) {
launchThreads(foo, 10);
std::cout << "Result (should be true): " << foo << "\n";
}
}代码会启动10个线程,每个线程都会将atomic_bool翻转成大量的偶数(100000次),并打印出布尔值。这种情况重复了20次。
编辑:对于那些想要运行这段代码的人,我使用的是具有两个内核的ubuntu11.10上的GCC 4.7快照。汇编的备选方案如下:
-std=c++0x -Wall -pedantic-errors -pthread发布于 2012-03-21 14:27:30
b = !b不是原子的,因为在C++源中有一个b的原子纯读(等价于b.load(),然后是一个单独的原子赋值给b (等效于b.store())。
在C++抽象机器中,没有任何东西使整个组合成为原子RMW操作,也没有将任意操作组合到原子RMW操作中的语法(除了将其放入CAS重试循环中)。
有两个选项可供使用:
atomic<bool>,使用一个可以是0或1的整数类型(例如atomic<int>或atomic<unsigned char>),然后用1表示它::原子标志(0);标志^= 1;//相当于flag.fetch_xor(1);
不幸的是,只有在循环中的整数types.
atomic<bool>上提供fetch_xor,直到它成功为止:std::原子标志(False);bool oldValue = flag.load();while (!flag.compare_exchange_weak(oldValue,!oldValue)) {}
不幸的是,x86编译器通常不会将这个循环优化为
asm中的lock xor byte [flag], 1;您将得到一个实际的cmpxchg重试循环。在实践中,cmpxchg重试循环很好,争用较低。在最坏的情况下,这不是没有等待,但是无锁的,因为至少有一个线程将取得进展,每次他们都重试。(实际上,硬件仲裁要复杂得多,核心甚至可以访问缓存行进行尝试。)
如果可能存在较高的争用性,请使用允许使用原子xor.的整数版本。
https://stackoverflow.com/questions/9806200
复制相似问题