muduo库-原子类AtomicIntegerT
C++中的原子操作有两种实现方式:
- C++11以后,提供st::atomic可以实现T类型数据的原子操作,主要包括:初始化、读取值、写值、自增自减(i.e.
前置或后置++)等。
- C++11以前的版本,需要用GCC编译器提供的原子操作接口,实现原子操作。
AtomicIntegerT模板类
muduo产生与C++11流行之前,因此用了第二种方案。实际上,Linux下面,C++11中的原子操作实现,也是用的第一种方案实现的。
自定义AtomicIntegerT模板:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
|
template<typename T> class AtomicIntegerT : noncopyable { public: AtomicIntegerT() :value_(0) { }
T get() { return __sync_val_compare_and_swap(&value_, 0, 0); } T getAndAdd(T x) { return __sync_fetch_and_add(&value_, x); } T addAndGet(T x) { return getAndAdd(x) + x; } T incrementAndGet() { return addAndGet(1); } T decrementAndGet() { return addAndGet(-1); } void add(T x) { getAndAdd(x); } void increment() { incrementAndGet(); } void decrement() { decrementAndGet(); } T getAndSet(T newValue) { return __sync_lock_test_and_set(&value_, newValue); }
private: volatile T value_; };
|
为了使用方便,同时避免重复命名、实例化、甚至编译,使用AtomicIntegerT包装int32_t,
int64_t,然后重定义,我们在.h文件中声明这2个
1 2 3
| typedef detail::AtomicIntegerT<int32_t> AtomicInt32; typedef detail::AtomicIntegerT<int64_t> AtomicInt64;
|
单元测试
主要针对AtomicInt64、AtomicInt32
这2个常用的、具体的类型,进行测试。
方法:通过构造实例对象后,调用成员函数get()、getAndAdd()、addAndGet()、incrementAndGet()、decrementAndGet(),对原子对象进行修改,然后根据返回值判断值是否为预期值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| { 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); }
...
|
相关知识点
GCC原子操作
GCC提供了一套原子操作的接口,可以实现原子操作。这些接口都是以__sync开头的,如__sync_fetch_and_add(),__sync_val_compare_and_swap()等。
原子自增操作:
1
| type __sync_fetch_and_add(type *ptr, type value)
|
原子赋值操作:
1
| type __sync_lock_test_and_set(type *ptr, type value)
|
使用这些原子操作时,编译时需要加-march=cpu-type
(CPU体系结构=CPU类型,可以指定为native)
volatile关键字
确保本条指令不会因为编译器的优化而省略,而且要求每次从内存直接读值,而不是读高速cache中的备份。
本文参考自:muduo笔记
原子类AtomicIntegerT