muduo笔记 原子类AtomicIntegerT<T>

原子操作

C++中的原子操作:
1)C++11以后,提供st::atomic<T>可以实现T类型数据的原子操作,主要包括:初始化、读取值、写值、自增自减(i.e. 前置或后置++)等。
2)对于C++11以前的版本,需要用GCC编译器提供的原子操作接口,实现原子操作。

AtomicIntegerT<T>模板类

muduo产生与C++11流行之前,因此用了第二种方案。实际上,Linux下面,C++11中的std::stomic实现,也是用的第一种方案实现的。
自定义AtomicIntegerT<T>模板:

/* GCC atomic operation see
* https://www.cnblogs.com/the-tops/p/6347584.html
* https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
*/
template<typename T>
class AtomicIntegerT : noncopyable
{
public:
    AtomicIntegerT()
    :value_(0)
    { }

    T get()
    {
        // CAS(compare and swap)
        // in gcc >= 4.7: __atomic_load_n(&value, __ATOMIC_SEQ_CST)
        return __sync_val_compare_and_swap(&value_, 0, 0);
    }
    // 先fetch获取值(value_),然后再add加x
    T getAndAdd(T x)
    {
        // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST)
        return __sync_fetch_and_add(&value_, x);
    }
    // getAndAdd()中已经用原子操作改变了value_值,这里是通过值传递方式返回 old value_ + x
    T addAndGet(T x)
    {
        return getAndAdd(x) + x;
    }
    // 前缀式递增,相当于++value_
    T incrementAndGet()
    {
        return addAndGet(1);
    }
    // 前缀式递减,相当于--value_
    T decrementAndGet()
    {
        return addAndGet(-1);
    }
    // 求和,相当于value_ = value_ + x
    void add(T x)
    {
        getAndAdd(x);
    }
    // 单纯递增,不关心返回值
    void increment()
    {
        incrementAndGet();
    }
    // 单纯递减,不关心返回值
    void decrement()
    {
        decrementAndGet();
    }
    // 先fetch old value_,然后set value_ = newValue
    T getAndSet(T newValue)
    {
        // in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST)
        return __sync_lock_test_and_set(&value_, newValue);
    }

private:
    volatile T value_;
};

为了使用方便,同时避免重复命名、实例化、甚至编译,使用AtomicIntegerT包装int32_t, int64_t,然后重定义,我们在.h文件中声明这2个

// namespace muduo::detail
typedef detail::AtomicIntegerT<int32_t> AtomicInt32;
typedef detail::AtomicIntegerT<int64_t> AtomicInt64;

单元测试

主要针对AtomicInt64、AtomicInt32 这2个常用的、具体的类型,进行测试。

方法是通过构造实例对象后,调用成员函数get()、getAndAdd()、addAndGet()、incrementAndGet()、decrementAndGet(),对原子对象进行修改,然后根据返回值判断值是否为预期值。

// AtomicInt64 的测试
{
    AtomicInt64 a0;
    assert(a0.get() == 0);
    assert(a0.getAndAdd(1) == 0);
    assert(a0.get() == 1);
    assert(a0.addAndGet(2) == 3);
    assert(a0.get() == 3);
    assert(a0.incrementAndGet() == 4);
    assert(a0.get() == 4);
    a0.increment();
    assert(a0.get() == 5);
    assert(a0.addAndGet(-3) == 2);
    assert(a0.getAndSet(100) == 2);
    assert(a0.get() == 100);
}

// AtomicInt32 的测试类同,只需要修改a0的类型为AtomicInt32即可,具体代码略
... 

知识点

gcc原子操作

原子自增操作

type __sync_fetch_and_add(type *ptr, type value)

原子比较和交换(设置)操作

type __sync_val_compare_and_swap(type *ptr, type oldval type newval)
bool __sync_bool_compare_and_swap(type *ptr, type oldval type newval)

原子赋值操作

type __sync_lock_test_and_set(type *ptr, type value)

使用这些原子操作,编译时需要加-march=cpu-type (CPU体系结构=CPU类型,可以指定为native)

volatile关键字

确保本条指令不会因为编译器的优化而省略,而且要求每次从内存直接读值,而不是读高速cache中的备份。

volatile T value_;

参考

C++11开发中的Atomic原子操作 | cnblogs

Atomic/GCCMM/AtomicSync | wiki

无锁队列的实现 | coolshell


muduo库其它部分解析参见:muduo库笔记汇总

posted @ 2022-02-27 20:44  明明1109  阅读(366)  评论(0编辑  收藏  举报