生产者与消费者模型+POSIX信号量

生产者与消费者模型(以做面与吃面为例)
一个场所(只有一口锅,也就是放置数据的地方只有一个)、两种角色、三种关系(生产者之间互斥(我放的时候,你就不能放,因为会造成数据混乱)、消费者之间互斥(因为你们俩没必要抢同一数据处理吧)、生产者与消费者之间是同步+互斥(总不能面做到一半你就吃吧))。
这个模型用来:解耦和(如果在没有场所保存数据的情况下,也就是生产者生产出数据就得交给消费者来处理数据,如果直接交给消费者的话,会存在一个问题,生产者与消费者的代码就写到一块去了,这时候他们的耦和性比较强,并且还存在问题是假如生产者生产数据快,而消费者处理数据慢,那么数据就会丢失,为了防止被数据丢掉,就得做一个缓冲区,这就是前面提到的场所,这个缓冲区的第一功能就是解耦和,生产者和消费者之间并没有数据交互,只是分别和缓冲区打交道,第二功能是支持忙闲不均,就是解决数据丢失问题的,第三功能,支持并发,多个生产者可以同时往缓冲区里面放数据,消费者也可以同时去取)。也就是说,在这个模型中这个场所非常关键,因为这么多生产者和消费者都要去操作这个场所,所以它得保证安全,就是同步与互斥。
这些优点都是通过这个场所(缓冲区)来提供,但是因为两个角色有可能同时操作场所,因此要保正场所的安全。
生产者之间应该保持互斥关系、消费者与消费者之间也是互斥关系、生产者与消费者之间应该保持同步+互斥。
缓冲区可以是队列或线性表。

class BlockQueue
{
//std::queue//队列它不是线程安全的,因为STL容器在设计之初就是追求性能出发的,
                  //不能在这个队列里面加锁,因为会降低性能,
                  //队列是先进先出,首先队列有数据才能获取数据,所以队列本身就能在一对一的情况下保持同步+互斥,
                  //如果一个生产者与一个消费者进行通信的话,队列根本就不用锁
public:
BlockQueue();
~BlockQueue();
bool QueuePush(int data);
bool QueuePop(int &data);

private:
std::queue<int> _queue;//没有上限,这样容易处问题
                                      //一瞬间大量数据过来,导致资源耗尽,程序崩溃
int capacity;//限制队列中结点最大数量
pthread_mutex_t _mutex;
pthread_cond_t cond_product;
pthread_cond_t cond_consumer;
}

代码

POSIX信号量

POSIX信号量和System V信号量作用相同,都是用于实现进程间同步与互斥的。但POSIX还可以用于线程间的同步与互斥。
功能:实现线程间同步与互斥
本质:一个计数器,做资源计数的,判断当前是否可以对临界资源进行操作,如果不能操作的话,提供等待。+唤醒+等待队列

原理

一、互斥原理:只具有0/1计数时,就可以实现互斥。
初始计数为1。1表示当前只有一个线程能够获取资源。获取资源后-1;因为这个计数器本身就是一个临界资源,所以它的操作必须是原子操作。
临界资源操作完毕后,计数+1,并唤醒等待上的队列。
计数为0,其他线程惊醒等待,将pcb加入到等待队列,此时它们的状态是可中断休眠。
流程:
1、定义信号量sem_t sem;
2、初始化信号量 sem_init(&sem, 0);
参数1:信号量变量
参数2:0用于线程间的同步与互斥;!0用于进程间的同步与互斥。
参数3:信号量计数器初始值
3、信号量并不是锁,而是判断计数是否可以对临界资源进行操作。
sem_wait(&sem);//阻塞等待,对计数进行判断,是否大于0,若大于0则函数立即正确返回前计数-1,程序流程继续向下可以操作临界资源;若=0,则认为当前不能对临界资源进行操作,则线程等待。
sem_trywait(&sem);//非阻塞,当前计数=0,直接报错返回
sem_timedwait();//限时阻塞,当前计数=0,等待时间超时后报错返回
4、计数+1,促使其他线程操作条件满足,唤醒等待队列上的线程 sem_post(&sem);
5、销毁信号量 sem_destroy(&sem);

二、同步原理:对程序逻辑进行控制,对临界资源合理操作的控制。
通过判断当前是否能够对临界资源进行操作,不能操作(计数=0)则等待,其他线程促使等待判断后,对计数+1,唤醒等待的线程。
信号量的初始化很重要,有多少资源就初始化成多少。就像停车场的停车位,来一个车,停车位减一,走一个车,停车位加一。

信号量的同步与条件变量的同步实现区别:

1、信号量不用搭配互斥锁使用;
2、条件变量本身不具备条件的判断,是交给用户进行判断的,但是信号量提供条件的判断而其条件的判断就是通过计数器。

实现:POSIX标准,支持多平台。
使用信号量实现生产者消费者模型

//实现线程安全的环形队列
class RingQueue
{
private:
  std::vector<int> _queue;
  int capacity;
  int _read;
  int _write;
  sem_t _lock;//用信号量实现互斥
  sem_t _idle_space;//用信号量实现同步,也就是用环形队列的空闲空间,生产者入队数据之前,初始化成capacity。
  sem_t _data_space;//用于判断是否队列有数据,消费者获取数据之前判断有数据的空间有多少,判断能否获得数据,初始化为0。

public:
 void QueuePush(int data);
 void QueuePop(int &data);
}

代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值