高并发服务器学习之原子性

        在多线程中对于竞争资源问题,最容易想到的就是加锁。在使用资源前对资源加锁,这样其他线程就不能访问,知道该线程释放;但在高并发服务器中,加锁会带来效率上的问题,显然不能满足高性能的要求,为了解决这个问题就要使用原子性。现在几乎所有的CPU指令都支持CAS的原子操作,X86下对应的是 CMPXCHG 汇编指令。有了这个原子操作,我们就可以用其来实现各种无锁(lock free)的数据结构。

// 原子自增操作
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

上面列出的就是几个常用的原子性,在linux中gcc都已实现可直接使用,具体说明可以查看手册学习。

在C++11中的STL中的atomic类的函数可以让你跨平台。(完整的C++11的原子操作可参看 Atomic Operation Library)

1
2
3
4
5
6
template < class T >
bool atomic_compare_exchange_weak( std::atomic* obj,
                                    T* expected, T desired );
template < class T >
bool atomic_compare_exchange_weak( volatile std::atomic* obj,
                                    T* expected, T desired );

下面还是直接上作者自己封装的原子性类。

 class AtomicIntegerT{
public:  
AtomicIntegerT()    : value_(0)  {  }
   
private: 
// uncomment if you need copying and assignment  

AtomicIntegerT(const AtomicIntegerT& that) : value_(that.get()) {}
AtomicIntegerT& operator=(const AtomicIntegerT& that) { getAndSet(that.get()); return *this; }
public:

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_;

};

typedef detail::AtomicIntegerT AtomicInt32;
typedef detail::AtomicIntegerT AtomicInt64;


 
   
  
 该类实现也很易懂,注意的就是成员变量中volatile关键字的作用:作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。 
  
简单地说就是防止编译器对代码进行优化;通俗点说就是:当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,
而不是使用保存在寄存器中的备份。即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存

你可能感兴趣的:(服务器SERVER)