条件变量
条件变量的详细介绍在之前的一篇博文中:
互斥器是加锁原语,用来排他性地访问共享数据,使用mutex时,我们希望立即拿到锁,然后尽快访问数据,用完之后尽快解锁,这样才能不影响并发性和性能。
先介绍moduo中condition的封装:
- class Condition : boost::noncopyable
- {
- public:
- explicit Condition(MutexLock& mutex) : mutex_(mutex)
- { pthread_cond_init(&pcond_,NULL); }
- ~Condition() { pthread_cond_destroy(&pcond_); }
- void wait() { pthread_cond_wait(&pcond_, mutex_.getPthreadMutex()); }
- void notify() { pthread_cond_signal(&pcond_ ); }
- void notifyAll() { pthread_cond_broadcast(&pcond_); }
- private:
- MutexLock& mutex_;
- pthread_cond_t pcond_;
- };
如果需要等待某个条件成立,应该使用条件变量。条件变量的学名叫管程(monitor)。
对于wait端:
1.必须与mutex一起使用,该布尔表达式的读写需受此mutex保护
2.在mutex已上锁的时候才能调用wait()
3.把判断布尔条件和wait()放到while循环中
代码:
- muduo::MutexLock mutex;
- muduo::Condition cond(mutex);
- std::deque<int> queue;
- int dequeue()
- {
- MutexLockGuard lock(mutex);
- while(queue.empty()) //必须用循环;必须在判断之后再wait()
- {
- cont.wait(); //这一步会原子地unlock mutex并进入等待。不会与enqueue死锁;wait()执行完毕后会自动重新加锁
- }
- assert(!queue.empty()); //判断条件是否变化
- int top = queue.front();
- queue.pop_front();
- }
- void enqueue(int x)
- {
- MutexLockGuard lock(mutex);
- queue.push_back(x);
- cond.notify(); //muduo:Condition采用了notify()和notifyAll()为函数名,避免重载signal这个术语(如上)
- }
上面代码中必须用while循环来等待条件变量,而不用if语句。原因是spurious wakeup。
条件变量是非常底层的同步原语,很少直接使用,一般用它来实现高层的同步措施,如CountDownLatch。
倒计时(CountDownLatch)是一种常用且易用的同步手段。主要有两种用途:
1.主线程发起多个子线程,等这些子线程各自都完成一定的任务之后,主线程才继续执行。通常用于主线程等待多个子线程完成初始化。
2.主线程发起多个子线程,子线程都等待主线程,主线程完成其他一些任务之后通知所有子线程开始执行。通常用于多个子线程等待主线程发出“起跑”命令。
CountDownLatch接口:
- class CountDownLatch : boost::nonqcopyable
- {
- public:
- explicit CountDownLatch(int count); //倒数几次
- void wait(); //等待计数值变为0
- void countDown(); //计数减1
- private:
- mutable Mutexlock mutex_;
- Condition condition_;
- int count_;
- };
CountDownLatch实现:
- /* 构造函数:mutex_应先于condition_构造 */
- class CountDownLatch
- {
- public:
- CountDownLatch(int count): mutex_(),condition_(mutex_),count_(count) {}
- private:
- mutable MutexLock mutex_; //顺序很重要,先mutex后condition
- Condition condition_;
- int count_:
- }
- void CountDownLatch::wait()
- {
- MutexLockGuard lock(mutex_);
- while(count_ > 0)
- condition_.wait();
- }
- void CountDownLatch::countDown()
- {
- MutexLockGuard lock(mutex_);
- --count_;
- if (count == 0)
- condition_.notyfiAll();
- }
互斥器和条件变量构成了多线程编程的全部必备同步原语,用它们即可完成任何多线程同步任务,二者不能相互替代。