信号量实现生产者消费者问题

生产者/消费者问题是一个多进程进行同步的问题,需要使用信号量(semaphore)进行相关资源的控制,实现并发。一些关于并发的基础概念如下:
原子操作 一组不可分割的函数或操作。这类函数或操作的执行是不可以被中断的。
临界区 进程中一段需要访问共享资源的代码,共享资源一次只能允许一个进程访问,系统要保证进入临界区的进程不超过一个。 正常执行可以并行,临界区代码执行只能串行。
在这里插入图片描述

解决并发问题的核心:控制对共享资源的访问

信号量(semaphore)
用于在进程间发送信号的整形变量,该变量定义3个原子操作:

1.初始化:信号量的初始值为非负整数
2.semSignal(V):将信号量加1,如果之后信号量的值大于等于零,进程唤醒该信号量上等待的一个进程,并继续自己的执行。
3.semWait(P):将信号量减1,如果之后信号量的值为负数,调用semWait的函数将阻塞,否则进程继续执行。

互斥锁和01信号量的区别:互斥锁执行上锁和开锁的进程必须为同一进程,01信号灯可以是不同进程。

生产者/消费者问题
有一个或多个生产者,不停生产数据,将所生产的数据放到一个缓冲区中。同时有一个消费者将数据从缓冲区中取出。用信号量解决该问方法伪代码如下:

semaphore full = 0;
semaphore empty = BUFFER_SIZE;
semaphore mutex = 1Producer() 			Consumer() 
{					{
	produce();			P(full);
	P(empty);			P(mutex);
	P(mutex);			take();
	put();				V(mutex);
	V(mutex);			V(empty);
	V(full);			consume();
}					}

生产者:生产物品 -> 请求访问缓冲区空闲的资源 (没有资源阻塞,有资源继续执行) -> 给缓冲区上锁 -> 向缓冲区添加物品 -> 给缓冲区解锁 -> 释放可用面包资源

消费者:请求访问可用物品资源(没有资源阻塞,有资源继续执行)-> 给缓冲区上锁 -> 从缓冲区拿走物品 -> 给缓冲区解锁 -> 释放可用缓冲区资源 -> 消费物品

对信号量的理解 信号量的PV操作实际上是某个进程使用和释放某资源,如果进程想要使用资源,当前资源为0那么进程就会阻塞等待资源。

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生产者消费者问题可以借助信号量来解决。使用记录型信号量时,需要记录当前缓冲区中可用物品的数量和已有物品的数量。具体实现如下: 定义一个记录型信号量,其中两个计数器分别用来记录可用缓冲区数量和已有物品数量。 ```c++ typedef struct { int value; pthread_mutex_t mutex; pthread_cond_t cond; } sem_t; void sem_init(sem_t* sem, int value) { sem->value = value; pthread_mutex_init(&sem->mutex, NULL); pthread_cond_init(&sem->cond, NULL); } void sem_wait(sem_t* sem) { pthread_mutex_lock(&sem->mutex); while (sem->value <= 0) { pthread_cond_wait(&sem->cond, &sem->mutex); } sem->value -= 1; pthread_mutex_unlock(&sem->mutex); } void sem_post(sem_t* sem) { pthread_mutex_lock(&sem->mutex); sem->value += 1; pthread_cond_signal(&sem->cond); pthread_mutex_unlock(&sem->mutex); } int buffer_size = 10; int in = 0; int out = 0; int buffer[10]; sem_t empty_buffer, full_buffer; void producer() { int item = produce_item(); sem_wait(&empty_buffer); buffer[in] = item; in = (in + 1) % buffer_size; sem_post(&full_buffer); } void consumer() { sem_wait(&full_buffer); int item = buffer[out]; out = (out + 1) % buffer_size; sem_post(&empty_buffer); consume_item(item); } int main() { sem_init(&empty_buffer, buffer_size); sem_init(&full_buffer, 0); // create producer and consumer threads return 0; } ``` 在上面的代码中,`sem_t` 是一个记录型信号量结构体,其中 `value` 记录当前可用缓冲区或已有物品的数量,`mutex` 用于加锁互斥,`cond` 用于阻塞/唤醒等待线程。在 `sem_init` 中进行初始化,其中 `value` 指定初始可用数量。`sem_wait` 等待可用物品数量不为0,然后减少一个可用物品数量。`sem_post` 增加一个可用物品数量并唤醒等待线程。 在生产者函数 `producer` 中,先生产一个物品,然后等待可用缓冲区不为满,将物品加入缓冲区,并增加已有物品计数。在消费者函数 `consumer` 中,等待已有物品数量不为0,从缓冲区取出一个物品,并减少已有物品计数,释放一个可用缓冲区。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值