muduo读书笔记02

来源:互联网 发布:三维编程 编辑:程序博客网 时间:2024/06/11 02:43

并发编程有两种基本模型:

  • message passing(消息传递)
  • shared memory(共享内存)

在分布式系统中,运行在多台机器上的多个进程的并行编程只有一种实用模型:message passing

线程同步的四项原则:

  • 尽量不要共享对象
  • 使用高级的并发编程构件
  • 使用底层原语时,尽量使用非递归的互斥锁和条件变量,慎用读写锁,不要用信号量
  • 除了使用atomic整数之外,不自己编写lock-free代码,也不要用内核级同步原语

互斥器

互斥器保护了临界资源,任何时刻最多只有一个线程在此mutex划出的临界区内活动。

  • 用RAII手法封装mutex的创建、销毁、加锁、解锁这四个操作
  • 只使用不可重入的mutex
  • 不手工调用lock()和unlock()函数,一切交给栈上的Guard对象的构造和析构函数负责。
  • 每次构造Guard对象的时候,思考已经持有的锁,防止因加锁顺序不同而导致死锁。

条件变量(condition variable)

如果需要等待某个条件成立,我们应该使用条件变量(condition variable)。条件变量指一个或多个线程等待某个布尔表达式为真,即等待别的线程”唤醒”它。条件变量的学名叫管程(monitor)。

对于wait端:

  • 必须与mutex一起使用,该布尔表达式的读写需受此mutex保护
  • 在mutex已上锁的时候才能调用wait()
  • 把判断布尔条件和wait()放到while循环中
pthread_mutex_lock(&lock);while (condition_is_false) {    pthread_cond_wait(&cond, &lock);}

用while的原因是避免spurious wakeup(虚假唤醒),实际上pthread_cond_wait的返回不仅仅是pthread_cond_signal和pthread_cond_broadcast导致的,还会有一些假唤醒,也就是spurious wakeup。

对于signal/broadcast端:

  • 不一定要在mutex已上锁的情况下调用signal(理论上)
  • 在signal之前一般要修改布尔表达式
  • 修改布尔表达式之前通常要用mutex保护
  • signal表示资源可用,broadcast用于表明状态变化

不要用读写锁和信号量

互斥锁可以替代读写锁
条件变量+互斥锁可以替代信号量

线程安全的Singleton实现

双重锁是靠不住的

template<typename T>class Singleton{private:    Singleton();    ~Singleton();    static void Init()    {        _value = new T();    }    static T* _value;    static phread_once_t _ponce;public:    static T& instance()    {        pthread_once(&_ponce,&Singleton::Init());        return _value;    }}template<typename T>T* Singleton<T>::_value = NULL;template<typename T>phread_once_t  Singleton<T>::_ponce = PTHREAD_ONCE_INIT;