线程同步的四项准则

  • 最低限度的共享对象,缩小须要同步的场合
  • 应用高级的并发构件,如TaskQueue,Producer-Consumer Queue,CountDownLatch等
  • 非不得已应用底层同步原语时,只应用非递归的互斥器和条件变量,慎用读写锁,不要应用信号量
  • 除了应用atomic整数外,不本人编写lock-free代码,也不要应用内核级同步原语

互斥器(mutex)

应用准则

  • 应用RAII手法封装mutex的创立、销毁、加锁、解锁

    • 保障了锁的失效期间等于一个作用域(Scoped Locking),在死锁产生时有助于定位
    • 保障了不手工调用lock和unlock
    • 保障了不跨过程和线程调用锁
    • 保障了不遗记解锁和反复加锁
  • 只应用非递归的mutex(即不可重入的mutex)
  • 每次结构Guard对象时,思考一路上曾经持有的锁(函数调用栈),避免因桎梏程序不同导致的死锁

为什么只应用非递归的mutex

  • 同一个线程能够反复对递归的mutex加锁,但不能反复对非递归的mutex加锁
  • 在同一个县城里屡次对非递归的mutex加锁会导致死锁
  • 两者性能差异不大

起因

  • 非递归的锁能提前暴露出编程问题

死锁

  • 除了线程间的死锁,单个线程也会造成死锁
  • 在保障应用Scoped Locking时,能够通过剖析调用栈失去起因

条件变量

应用条件变量实现的BlockingQueue

muduo::MutexLock mutex;muduo::Condition cond(mutex);std::deque<int> queue;int dequeue(){    MutexLockGuard lock(mutex);    while(queue.empty()){        cond.wait(); // unlock mutex and wait (原子地)    }    assert(!queue.empty());    int top = queue.front();    queue.pop_front();    return top;}void enqueue(int x){    {    MutexLockGuard lock(mutex);    queue.push_back(x);    }    cond.notify(); // wakeup the wait side}
  • 每次退出都调用notify(),而不是notifyall()是为了防止惊群效应
  • 不只在0->1的时候notify(),而是每加一次告诉一次,是当存在多个消费者时,能高效地唤醒他们,不然只唤醒了一个
  • 详见 https://book.douban.com/annot...

应用条件变量实现CountDownLatch(倒计时)

class CountDownLatch : boost::noncopyable{    public:        explicit CountDownLatch(int count);        void wait();        void countDown();    private:        mutable MutexLock mutex_;        Condition condition_;        int count_;}void CountDownLatch::wait(){    MutexLockGuard lock(mutex_);    whilt(count_>0){        condition_.wait();    }}void CountDownLatch::countDown(){    MutexLockGuard lock(mutex_);    --count_;    if(count_ == 0){        condition_.notifyAll();    }}

封装MutexLock、MutexLockGuard、Condition的实现

class MutexLock : boost::noncopyable{    public:        MutexLock()        :holder_(0)        {            pthread_mutex_init(&mutex_NULL);        }        ~MutexLock()        {            assert(hoilder_ == 0);            pthread_mutex_destory(&mutex);        }        bool isLockedByThisThread(){            return holder_ == CurrentThread::tid();        }                void assertLocked(){            assert(isLockedByThisThread());        }                void lock(){            pthread_mutex_lock(&mutex);            holder_ = CurrentThread::tid();        }        void unlock(){            holder_ = 0;            pthread_mutex_unlock();        }        pthread_mutex_t* getPthreadMutex(){            return &mutex;        }    private:        pthread_mutex_t mutex_;        pid_t holder_; }class MutexLockGuard : boost::noncopyable{    public:        explicit MutexLockGuard(MutexLock& mutex)        :mutex_(mutex)         {            mutex_.lock();        }                ~MutexLockGuard(){            mutex_.unlock;        }    private:        MutexLock& mutex_;}#define MutexLockGuard(x) static_assert(false,"Missing mutex guard variable name!")class Condition : boost::noncopyable{    public:        explicit Condition(MutexLock& mutex)        :mutex_(mutex)        {            pthread_cond_init(&pcond_,NULL);        }        ~Condition(){            pthread_cond_destory(&pcond_);        }        void wait(){            pthread_cond_wait(&pcond_,mutex_.getPthreadMutex());        }        void notify(){            pthread_cond_signal(&pcond_);        }                void notifyAll(){            pthread_cond_boardcast(&pcond);        }    private:        MutexLock& mutex_;        pthread_cond_t pcond_;}

小结

  • 线程同步的四项准则:尽量应用高级同步设施
  • 对于其余的工作,应用一般互斥器和条件变量,采纳RAII手法和Scooped Locking