2012-03-21 36 views
33

天真布尔非如何以原子方式否定std :: atomic_bool?

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一个larrge,甚至,次数(100000),和打印数出布尔值。这重复了20次。

编辑:对于那些想要运行这段代码的人,我在两个内核的Ubuntu 11.10上使用GCC 4.7快照。编译选项是:

-std=c++0x -Wall -pedantic-errors -pthread 
+0

纵观规格,原子类型,如'的std :: atomic_bool'和'的std ::原子'没有像'operator!'这样的布尔运算符。所以'!b'确实涉及原子类型的(隐式)转换运算符。由于我不确定如何提供您需要的功能,因此我没有做出这个答案。 – 2012-03-21 14:15:24

+0

@LucDanton对,我找不到任何关于原子的专门操作符'!',所以我确信转换发生了,而且很可能是比赛的原因。 – juanchopanza 2012-03-21 14:19:13

+1

这就是我在运行程序时得到的结果:抛出'std :: system_error'的实例后调用terminate# – 2012-03-21 14:21:32

回答

25

b = !b,因为它是由两者读取和写入,其每一个是一个原子操作的不是原子。

有两种选择使用:

  1. 代替atomic<bool>,使用一体型(例如atomic<int>),其可以是0或1,和异或将其与1:

    std::atomic<int> flag(0); 
    
    flag ^= 1; //or flag.fetch_xor(1); 
    

    不幸的是,fetch_xor不在atomic<bool>上提供,仅限于整型。

  2. 在一个循环中执行比较/交换操作,直到成功:

    std::atomic<bool> flag(false); 
    
    bool oldValue = flag.load(); 
    while (!flag.compare_exchange_weak(oldValue, !oldValue)) {} 
    
+0

第二个似乎造成活锁,至少在理论上。 – zch 2012-03-21 14:42:01

+4

@zch:我不这么认为。如果另一个线程成功修改了变量,它只需要再次循环。所以一些工作总是至少在一个线程上完成 - 换句话说,这是无锁的,但不是等待。 – interjay 2012-03-21 14:52:14

+0

选项2很适合我的例子。这是原子类型更新操作的标准模式吗? – juanchopanza 2012-03-21 17:25:00

相关问题