muduo_base 源码分析:AtomicIntegerT

muduo_base 源码分析:AtomicIntegerT

为什么需要原子性操作?

    所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何context switch (切换到另一个线程)。

    以前见过一道面试题:i++ 是否为原子操作?

    答案是i++ 不是原子操作,i++ 操作可分为三步,(1)从内存中读i 的值到寄存器,(2)对寄存器值+1,(3)把新的 i 的值写入内存。其中任何一步都有可能被多个线程干扰。

time   Thread 1           Thread 2

0          loadeax, i

1                               loadeax, i

2          addeax, 1          

3                               addeax, 1

4          storei, eax

5                               storei, eax

在多线程环境下要让i++的结果只 +1,可使用锁(lock(); i++;unlock();),但是锁是服务器性能的四大杀手之一,系统开销较大。

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(可选择native,编译器自动识别CPU 类型)

AtomicIntegerT类图 

 muduo_base 源码分析:AtomicIntegerT_第1张图片

AtomicIntegerT代码

//muduo/muduo/base/Atomic.h
template
class AtomicIntegerT : boost::noncopyable
{
public:
	AtomicIntegerT()
		: value_(0)
	{
	}

	T get()            //获取value_
	{
		// in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST)
		return __sync_val_compare_and_swap(&value_, 0, 0);
	}

	T getAndAdd(T x)   //先获取value_ 后 +x
	{
		// in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST)
		return __sync_fetch_and_add(&value_, x);
	}

	T addAndGet(T x)   //先给value_ +x 后获取
	{
		return getAndAdd(x) + x;
	}

	T incrementAndGet()    //给value_ +1并返回
	{
		return addAndGet(1);
	}

	T decrementAndGet()    //给value_ -1并返回
	{
		return addAndGet(-1);
	}

	void add(T x)          //给value_ +x
	{
		getAndAdd(x);
	}

	void increment()       //给value_ +1
	{
		incrementAndGet();
	}

	void decrement()       //给value_ -1
	{
		decrementAndGet();
	}

	T getAndSet(T newValue)//先获取value_值,再将value_设置为newValue
	{
		// in gcc >= 4.7: __atomic_store_n(&value, newValue, __ATOMIC_SEQ_CST)
		return __sync_lock_test_and_set(&value_, newValue);
	}

private:
	volatile T value_;
};

volatile 作用

    volatile作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。简单地说就是防止编译器对代码进行优化

当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,而不是使用保存在寄存器中的备份。即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

详解见:http://www.zhihu.com/question/31459750

 

你可能感兴趣的:(网络编程)