muduo基础库学习(二)

1. Types.h

//implicit_cast<ToType>(expr)
//From type can be inferred; so one argument is ok;
template<typename To, typename From>
inline To implicit_cast(From const &f)
{
  return f;
}

template<typename To, typename From>
inline To down_cast(From* f)
{
  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);
}

implicit_cast用于向上转换(派生类->基类),可以在编写代码时提醒使用了隐式转换,用于促使自己编写更高质量代码。例如

class B
{
public:
	virtual void foo(){}
};
class D : public B
{
public:
	void foo(int x){}
};
int main()
{
	B* pb;
	D* pd = NULL;
	//pb = pd;
	pb = implicit_cast<B*, D*>(pd);
	return 0;
}

上述情况若直接pb=pd,易忽略派生类到基类的隐式转换;
down_cast则是基类转换为派生类的向下转换,需要使用RTTI(运行时检测机制)检测对象指针类型From* 到To* 是可以转换的,或者From*为空指针时。最终实现转换使用static_cast;

2. gcc原子操作

原子性操作:
x++
从内存读取x的值到寄存器中,寄存器+1, 再把新值写入原内存地址;

timethread1thread2
1load eax, x
2load eax, x
3add eax, 1
4add eax, 1
5store x, eax
6store x, eax

假设x原始的值为1,那么两线程执行后,x的值为2,然而我们想要的结果为3;可以采用锁来进行临界操作达到目的,但会造成性能变差,所以原子操作很有必要(线程安全的)。
gcc提供的原子操作将这三步操作看作作为一步处理,gcc常用的原子操作:

//atomic.h

 T getAndAdd(T x)
  {
    // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST)
    //原子自增操作
    return __sync_fetch_and_add(&value_, x);//返回value增加前的值
  }
  
T get()
  {
    // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST)
    //原子比较和交换操作(设置)操作
    return __sync_val_compare_and_swap(&value_, 0, 0);
  }

T getAndSet(T newValue)
  {
    // in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST)
    //原子赋值操作
    return __sync_lock_test_and_set(&value_, newValue);
  }

注:使用这些原子操作时,编译时需要加 -march=cpu-type cpu-type常设为"native",自动检测本机cpu类型

无锁队列的实现(CAS实现方式)

EnQueue(x)
{
	q = new record();
	q->value = x;
	q->next = NULL;
	
	do{
		p = tail;//取链表尾指针快照;因为多线程环境,可能执行后p不指向链表尾节点
	}while(CAS(p->next, NULL, q) != true);
	//CAS原子操作,比较p->next和NULL;如果相等,p->next = q,返回true
	
	CAS(tail, p, q);//此时tail == p,所以tail = q,更新尾结点
}

若有线程T1,while中的CAS成功,则其他所有随后线程的CAS都会失败,因为此时tail->next == q,即tail不为尾节点;直到T1线程更新tail指针,其他线程可得到新的tail,正常执行。

不过这种方法可能会造成死循环:线程在执行CAS后还未更新指针就停掉或挂掉,其他线程就会进入死循环。改进方法自行百度无锁队列的实现。

3.volatile关键字

确保本条指令不会因为编译器的优化而省略,且要求每次直接读值。简单地说就是防止编译器对代码进行优化。 当使用volatile声明的变量值的时候,系统总是重新从它所在的内存读取数据,而不是使用保存在寄存器中的备份,即使它前面的指令刚从该处读取过数据。

4.muduo库中的编译选项

//my_muduo/CMakelists.txt

set(CXX_FLAGS
 -g //生成调试信息
 # -DVALGRIND
 -DCHECK_PTHREAD_RETURN_VALUE
 -D_FILE_OFFSET_BITS=64 //-D 定义宏
 -Wall //提示大部分警告
 -Wextra //提示一些额外的警告
 -Werror //将警告当作错误处理,停止编译
 -Wconversion //可能改变的值的隐式转换,警告
 -Wno-unused-parameter//未使用的参数,不给出警告
 -Wold-style-cast //c风格的转换,警告
 -Woverloaded-virtual //若函数声明隐藏了基类的虚函数,警告
 -Wpointer-arith //对函数指针或void*指针进行算数操作时,警告
 -Wshadow //局部变量遮盖另一个局部变量或全局变量,警告
 -Wwrite-strings //规定字符串常量的类型为const char*, 因此将此地址赋值给non-const char*时将产生警告;帮助在编译期发现企图修改字符串常量的代码
 -march=native 
 # -MMD
 -std=c++11
 -rdynamic
 )

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值