原子/互斥混合计数器

时间:2014-12-21 01:31:37

标签: c++11 atomic race-condition

我知道使用原子是危险的(几天前我看过Herb Sutter的3小时讲座),但是下面的用例对我来说似乎是合理的,简单而且包含得很好。

问题:(a)这有什么问题吗? (当然,必须有。)(b)这种基于混合原子/互斥的方法是否有名称? (c)是否有更简单的方法来实现同样的目标?

我们的目标是拥有一个线程安全的计数器类,我们可以调用attempt_invalidation(),知道如果计数为零,它只会将invalid标志设置为true 。课堂上没有其他公共方法,但我们会有一个专门设计用于RAII递增/递减计数器的朋友类。

 class hybrid_counter{
    friend class hybrid_counter_user; 

    bool                invalidated = false; 
    int                 counter_a = 0;  
    std::atomic_int     counter_b;
    std::mutex          mu;

    bool increment_safely(){
        std::lock_guard<std::mutex> gaurd(mu);
        if ( !invalidated )
            counter_a++;
        return invalidated;
    };
    void increment_dangerously(){
        counter_b++;
    };
    void decrement(){
        counter_b--; 
    };
 public:
    bool attempt_invalidation(){  
        if(counter_a + counter_b == 0){ 
            std::lock_guard<std::mutex> gaurd(mu);
            if(counter_a + counter_b == 0)
                invalidated = true;
        }
        return invalidated;
    };
};

这是知道如何正确使用计数器的朋友类:

class hybrid_counter_user{
public:
    hybrid_counter_user(hybrid_counter& hc){
        if(hc.increment_safely() == false) // is not yet invalidated
           c = &hc;
        else
           c = nullptr;
    };
    ~hybrid_counter_user(){
        if(c)
            c->decrement();
    };
    hybrid_counter_user(hybrid_counter_user&& old){ 
        c = old.c;
        old.c = nullptr;
    }
    hybrid_counter_user(hybrid_counter_user& other){
        c = other.c;
        if(c)
           c->increment_dangerously();
    }
private:
    hybrid_counter* c;
};

请注意,复制构造函数使用hybrid_counterother在范围内时仍然有效的事实,other的析构函数不能与increment_dangerously重新排序,因为两者都涉及相同的原子变量。 移动构造函数只是转移递减的责任。

0 个答案:

没有答案