赞
踩
为什么需要原子性操作?
我们考虑这样一种场景,两个线程对同一个变量同时x++操作。
x++ 在计算机的步骤:从内存中读取x的值到寄存器中,对寄存器加1,再把新值写回x所处的内存地址。
假设有如下时序图:
两个线程运行结束后,x等于11,正确应该是12,那要得出正确的结果,有两个方法:
第一种是锁:在X++ 之前加一把锁,加完解锁。这样就可以保证在同一时刻只有一个线程进入临界区域,对X进行读的操作,写的操作,当一个线程进入这个临界区域的时候,其他线程就不能访问这个临界区的资源,只能等到占用的线程unlook 的时候才能进入。多个线程访问资源的时候势必会发生锁竞争。锁竞争是高性能服务器四大杀手之一,我们应该尽可能的减少锁的使用。原子性操作可以实现这一目标。
第二种原子操作:原子性操作可以把X++的3步骤看成一个整体。现代的CPU都提供了原子性操作的相关指令。
这些是GCC 提供的原子性操作,当然前提是CPU支持原子性操作的指令。
- // 原子自增操作
- 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
-march=native 让GCC自动检测CPU是什么类型的体系结构
noncopyable 不可拷贝的实现就是将拷贝构造和赋值运算符做成私有的。
- #ifndef MUDUO_BASE_ATOMIC_H
- #define MUDUO_BASE_ATOMIC_H
-
- #include <boost/noncopyable.hpp>
- #include <stdint.h>
-
- namespace muduo
- {
-
- namespace detail
- {
- template<typename T>
- class AtomicIntegerT : boost::noncopyable
- {
- public:
- AtomicIntegerT()
- : value_(0)
- {
- }
-
- // uncomment if you need copying and assignment
- //
- // AtomicIntegerT(const AtomicIntegerT& that)
- // : value_(that.get())
- // {}
- //
- // AtomicIntegerT& operator=(const AtomicIntegerT& that)
- // {
- // getAndSet(that.get());
- // return *this;
- // }
- // 原子获取值
- 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<int32_t> AtomicInt32;
- typedef detail::AtomicIntegerT<int64_t> AtomicInt64;
- }
-
- #endif // MUDUO_BASE_ATOMIC_H
这些接口是模仿java 原子性操作类来写的.
原子性操作实现无锁队列:
volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。简单地说就是防止编译器对代码进行优化
当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,而不是使用保存在寄存器中的备份。即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存
muduo库中用到的编译器选项,加上编译选项可以使编写的代码质量更高。
-g 生成调试信息
-D 定义一个宏
-Wall 大部分的警告给出提示
-Wextra 给出一些额外的警告
-Werror 当出现警告时转为错误,停止编译
-Wconversion 一些可能改变值的隐式转换,给出警告
-Wno-unused-parameter 函数中出现未使用的参数,不给出警告
-Wold-style-cast C风格的转换,给出警告
-Woverloaded-virtual 如果函数的声明隐藏住了基类的虚函数,就给出警告
-Wpointer-arith 对函数指针和void*无类型指针做算数操作时,给出警告
-Wshadow 当局部变量遮盖住了另一个局部变量,或者全局变量时,给出警告
-Wwrite-strings 规定字符串常量的类型是const char[length],因此把这样的常量赋值给non-const char * 指针将产出警告,这些警告可以帮助在编译期间企图写入字符串常量的代码。
-march=native 指定cpu体系结构为本地平台。GCC是一个交叉编译器,它能够生成其他平台运行的代码,比如生成arm 平台的代码 。
typedef __gnu_cxx::__sso_string string; 短字符优化
阅读代码的时候可以看到发生了隐式转换
- template<typename To, typename From>
- inline To implicit_cast(From const &f) {
- return f;
- }
使用 static_cast 向下转型, 不依赖RTTI 机制向下转型。
- template<typename To, typename From> // use like this: down_cast<T*>(foo);
- inline To down_cast(From* f) { // so we only accept pointers
- // Ensures that To is a sub-type of From *. This test is here only
- // for compile-time type checking, and has no overhead in an
- // optimized build at run-time, as it will be optimized away
- // completely.
- if (false) {
- implicit_cast<From*, To>(0);
- }
-
- #if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI)
- assert(f == NULL || dynamic_cast<To>(f) != NULL); // RTTI: debug mode only!
- #endif
- return static_cast<To>(f);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。