Linux组件封装之二:Condition

本博文讨论Linux中的条件变量Condition的封装;

条件变量Condition 主要描述的是 线程间 的同步,即协作关系

Linux中的条件变量通常涉及以下几个函数:

int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_destroy(pthread_cond_t *cond);

一、条件变量类(Condition):

 1 #ifndef CONDITION_H_
 2 #define CONDITION_H_
 3
 4 #include "NonCopyable.h"
 5 #include "MutexLock.h"
 6 #include <pthread.h>
 7
 8 class Condition:NonCopyable //私有继承
 9 {
10     public:
11         Condition(MutexLock &mutex);
12         ~Condition();
13
14         void wait();//等待
15         void signal();//发送信号
16     private:
17         pthread_cond_t cond_;
18         MutexLock &mutex_; //wait函数的参数
19 };
20
21 Condition::Condition(MutexLock &mutex)
22     :mutex_(mutex)
23 {
24     pthread_cond_init(&cond_, NULL);
25 }
26
27 Condition::~Condition()
28 {
29     pthread_cond_destroy(&cond_);
30 }
31
32 void Condition::wait()
33 {
34     pthread_mutex_t  lock = mutex_.getMutex();
35     pthread_cond_wait(&cond_, &lock);
36 }
37
38 void Condition::signal()
39 {
40     pthread_cond_signal(&cond_);
41 }
42 #endif

这里要注意几点:

1)、wait必须在加锁的条件下方可使用;

2)、signal函数 一次唤醒一个线程,通常用来通知资源可用

3)、broadcast函数一次通知多个线程,用来通知状态的改变,滥用其,将会导致“惊群”问题;

使用wait函数时,必须使用while 循环。原因如下

1、采用 if 语句,最多只能判断一次;

2、为了描述方便,我们假设,这里有 5 个生产者(producer), 3 个消费者(consumer),缓冲区中最多能盛放 10 个产品;

a)假设现在缓冲区中已经存在10 个产品,如果再用生产者A抢到这把锁,就会调用 wait函数, 将producer函数阻塞,向consumer发送信号并释放该锁,

b)这时有一个consumer抢到 该锁,自然会消费一个产品,并释放该 锁,这时产品数还有 9 个;

c)由于抢锁 是不排队的,因此有可能是除了 A 之外的 producer(假设为B) 抢到锁,由于缓冲区未满(9个),因此会生产一个产品,这时缓冲区已满;

d)还是由于 抢锁是不排队的,这时有可能 A 又重新获得该锁,由于 if 只会判断一次, 而且也已近执行过,故,A生产者会生产一个产品,由于缓冲区已满,

这时如果再生产产品的话,就会造成溢出。

e)若采用 whilt 循环, A 若获得该锁,则会先判断 缓冲区的状态(是否已满),如果已满,则又会进入阻塞状态,不会造成溢出。

3、为了防止broadcast的干扰:如果有且仅有一个资源,使用broadcast会唤醒所有等待的线程,那么多个线程被唤醒,但最终只有一个能拿到资源,这就是所谓的“惊群效应”。

时间: 2024-11-10 09:26:31

Linux组件封装之二:Condition的相关文章

Linux组件封装(二)中条件变量Condition的封装

条件变量主要用于实现线程之间的协作关系. pthread_cond_t常用的操作有: int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond

Linux组件封装之五:生产者消费者问题

生产者,消费者问题是有关互斥锁(MutexLock).条件变量(Condition).线程(Thread)的经典案例: 描述的问题可以叙述为 生产者往buffer中投放产品,而消费者则从buffer中消费产品. 生产着消费者问题的难点在于: 为了缓冲区数据的安全性,一次只允许一个线程进入缓冲区投放或者消费产品,这个buffer就是所谓的临界资源. 生产者往缓冲区中投放产品时,如果缓冲区已满,那么该线程需要等待,即进入阻塞状态,一直到消费者取走产品为止. 相应的,消费者欲取走产品,如果此时缓冲区为

Linux组件封装(五)一个生产者消费者问题示例

生产者消费者问题是计算机中一类重要的模型,主要描述的是:生产者往缓冲区中放入产品.消费者取走产品.生产者和消费者指的可以是线程也可以是进程. 生产者消费者问题的难点在于: 为了缓冲区数据的安全性,一次只允许一个线程进入缓冲区,它就是所谓的临界资源. 生产者往缓冲区放物品时,如果缓冲区已满,那么需要等待,一直到消费者取走产品为止. 消费者取走产品时,如果没有物品,需要等待,一直到有生产者放入为止. 第一个问题属于互斥问题,我们需要使用一把互斥锁,来实现对缓冲区的安全访问. 后两个属于同步问题,两类

Linux组件封装(二) 条件变量Condition的封装

声明代码如下: 1 #ifndef CONDITION_H 2 #define CONDITION_H 3 4 #include <pthread.h> 5 #include "noncopyable.h" 6 7 class MutexLock; 8 9 10 class Condition : NonCopyable 11 { 12 public: 13 Condition(MutexLock &mutex); 14 ~Condition(); 15 16 vo

Linux组件封装之一:MUtexLock

本文对pthread_mutex_t 进行简易的封装: 互斥锁主要用于互斥,描述的是一种竞争关系,主要是一个 一种资源或者代码, 在一段时间内 至多能被一个程序访问. 而条件变量主要用于线程间同步, 描述的是一种协作关系. Linux中互斥锁的应用比较简单,通用的有以下几个函数: 1 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); 2 int pthread_mutex_l

Linux组件封装(六)——定时器的简单封装

在Linux中,有一种简单的定时器——timerfd,它通过查看fd是否可读来判断定时器时候到时. timerfd中常用的函数有timerfd_create.timerfd_settime.timerfd_gettime,这些函数都相对简单,我们可以到man手册来查看用法. 值得注意的是:create中的参数CLOCK_REALTIME是一个相对时间,我们可以通过调整系统时间对其进行调整,而CLOCK_MONOTIC是一个绝对时间,系统时间的改变不会影响它.在create中,flags一般设置为

Linux组件封装(八)——Socket的封装

我们要封装Socket,首先我们需要了解Socket需要哪些要素: 1) 首先,一个套接字创建后,需要绑定一块网卡的IP,以及连接的对口号,所以我们先封装InetAddr. 在class中,仅有的一个私有成员就是struct sockaddr_in类型的一个对象,我们需要将该对象的几种赋值与创建封装到类中,这样,我们仅需传递相应的IP与port即可获得一个addr. 在这里,我们为了方便获得该addr的IP及port,封装几个将addr转化为IP及port的函数,这样我们仅需调用函数即可. 然后

Linux组件封装之三:Thread

本篇我们将讨论线程Thread的封装: 一.线程类(Thread): 注意: 1.线程在默认情况下 是 joinable(可结合状态),需要手工调用 join函数(将其回收),也可以将其设置为detachable(分离状态),线程运行完毕后自动消亡: 2.Thread类采用static函数作为 pthread_create的回调函数,原因在于普通成员函数含有一个隐式参数(该类的对象 本身),所以函数指针类型除了有void*参数外,还有一个 Thread 对象的隐式参数,所以 这就与 void*(

Linux组件封装(一)中互斥锁MutexLock的封装

本文对Linux中的pthread_mutex_t做一个简易的封装. 互斥锁主要用于互斥,互斥是一种竞争关系,主要是某一个系统资源或一段代码,一次做多被一个线程访问. 条件变量主要用于同步,用于协调线程之间的关系,是一种合作关系. Linux中互斥锁的用法很简单,最常用的是以下的几个函数: int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); int pthread_mutex_