博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POSIX信号量-------多个生产者&单个消费者
阅读量:4181 次
发布时间:2019-05-26

本文共 3080 字,大约阅读时间需要 10 分钟。

问题描述

有多个线程:多个生产者线程和一个消费者线程程共享一个初始为空、固定大小为maxbuf的缓存(缓冲区)。多个生产者的工作是向缓冲区中存数据,只有缓冲区没满时,每次只能选择一个生产者把消息放入到缓冲区,否则必须等待,如此反复; 同时,只有缓冲区不空时,消费者才能从中取出消息,一次消费一个数据(即将其从缓存中移出),否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或者一个消费者从中取出消息。

问题分析

在前面的单个生产者&单个消费者问题中,我们使用了三个信号量来保证生成者与消费者的互斥。

对于生产者:

sem_wait(shared.empty); //empty--             sem_wait(shared.mutex); //获得互斥锁                 ....             sem_post(shared.mutex); //释放互斥锁         sem_post(shared.full); //full++

上面的代码可以保证每次只有一个生产者进入临界区,并且与消费者互斥访问。

对于消费者:

sem_wait(shared.full);  //full--             sem_wait(shared.mutex); //获得互斥锁                 ....             sem_post(shared.mutex); //释放互斥锁         sem_post(shared.empty); //empty--

上面的代码可以保证生产者与消费者之间的互斥。

通过上面的分析,我们发现之前的三个信号量就可以解决该问题,我们可以尝试用之前的代码框架来解决该问题。

问题解决(基于内存的信号量)

#include
#include
#include
#include
#include
#include
#define maxbuf 5#define pthread_n 4using namespace std;struct Shared{ int buf[maxbuf]; int next_in; sem_t mutex,empty,full;};Shared shared;void *produce(void *arg){ for(;;){ sem_wait(&shared.empty); sem_wait(&shared.mutex); if(shared.next_in >= maxbuf){ sem_post(&shared.mutex); return NULL; } if(shared.buf[shared.next_in] == 0){ shared.buf[shared.next_in] = shared.next_in; printf("Producer %d Successfully produce item %d\n",*((int *)arg),shared.next_in); } shared.next_in++; sem_post(&shared.mutex); sem_post(&shared.full); }}void *consume(void *arg){ for(int x=0;x

运行结果:

这里写图片描述

看起来好像运行正常,没什么问题。

我们修改一下创建的线程数量:4改为6(生产者数量大于缓冲区数量)

这里写图片描述

运行之后发现,程序陷入了死锁。所以原来的框架还是有问题。

修改

原来生产者线程中的代码:

sem_wait(&shared.empty);             sem_wait(&shared.mutex);                 if(shared.next_in >= maxbuf){                    sem_post(&shared.mutex);                    return NULL;                  }                 if(shared.buf[shared.next_in] == 0){                    shared.buf[shared.next_in] = shared.next_in;                    printf("Producer %d Successfully produce item %d\n",*((int *)arg),shared.next_in);                 }                 shared.next_in++;             sem_post(&shared.mutex);         sem_post(&shared.full);

添加一行代码:

sem_wait(&shared.empty);             sem_wait(&shared.mutex);                 if(shared.next_in >= maxbuf){                    sem_post(&shared.mutex);                    sem_post(&shared.empty); //退出前应该将empty的值+1                    return NULL;                  }                 if(shared.buf[shared.next_in] == 0){                    shared.buf[shared.next_in] = shared.next_in;                    printf("Producer %d Successfully produce item %d\n",*((int *)arg),shared.next_in);                 }                 shared.next_in++;             sem_post(&shared.mutex);         sem_post(&shared.full);

运行结果:

这里写图片描述

运行结果正常。

分析

我们来分析一下上面出现死锁的结果。

这里写图片描述

死锁时,shared.next_in的值为5,此时每个生产者线程都执行下面的代码:

if(shared.next_in >= maxbuf){                    sem_post(&shared.mutex);                 //   sem_post(&shared.empty);                    return NULL;                  }

此时由于生产者数量大于缓冲区个数,在进入临界区之前就已经将empty的值减一,但是此时并没有向缓存区生产数据,就会使得出现empty的值小于0的情况,从而造成死锁。因此返回时,得将empty的值加一。

你可能感兴趣的文章
mysql的JDBC连接工具类
查看>>
利用多线程(用到原子类AtomicInteger)往数据库批量插入大量数据
查看>>
多个线程操作数组
查看>>
定长线程池的应用
查看>>
ArrayBlockingQueue的简单使用
查看>>
Git 常用命令总结(一)
查看>>
Git 常用命令总结(二)
查看>>
JAVA 并发——synchronized的分析
查看>>
Echarts——使用 dataset 管理数据
查看>>
DES 加解密工具类
查看>>
SpringBoot多模块项目实践(Multi-Module)
查看>>
第一篇: 服务的注册与发现Eureka(Greenwich版)
查看>>
第二篇: 服务消费者(rest+ribbon)(Greenwich版本)
查看>>
第三篇: 服务消费者(Feign)(Greenwich版本)
查看>>
获取客户的真实IP地址
查看>>
第四篇: 熔断器(Ribbon+Feign)(Greenwich版本)
查看>>
Linux的常用命令(一)
查看>>
Linux的常用命令(二)
查看>>
第六篇: 分布式配置中心(Greenwich版本)
查看>>
SpringBoot | 配置logback-spring.xml
查看>>