POSIX信号量-------多个生产者&单个消费者

问题描述

有多个线程:多个生产者线程和一个消费者线程程共享一个初始为空、固定大小为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<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<semaphore.h>
#define maxbuf 5
#define pthread_n 4
using 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<maxbuf;x++){
         sem_wait(&shared.full);
             sem_wait(&shared.mutex);
                 if(shared.buf[x]!=0){
                    printf("Comsumer 0 Successfully consume item %d\n",shared.buf[x]);
                    shared.buf[x] = 0;
                 }
             sem_post(&shared.mutex);
         sem_post(&shared.empty);
      }
}

/*const char *m = "/mutex";
const char *e = "/empty";
const char *f = "/full";*/

int main(){
    pthread_t p_tid[pthread_n+1];
    int count[pthread_n];
    shared.next_in  = 0;
  /*  shared.mutex = sem_open(m,O_CREAT | O_EXCL,S_IRUSR | S_IWUSR, 1);
    shared.full  = sem_open(f,O_CREAT | O_EXCL,S_IRUSR | S_IWUSR, 0);
    shared.empty = sem_open(e,O_CREAT | O_EXCL,S_IRUSR | S_IWUSR, maxbuf);*/

    sem_init(&shared.mutex,0, 1);
    sem_init(&shared.full,0, 0);
    sem_init(&shared.empty,0, maxbuf);

    for(int x=0;x<pthread_n;x++){
        count[x] = x;
        pthread_create(&p_tid[x],NULL,&produce,&count[x] );
    }

    pthread_create(&p_tid[pthread_n],NULL,&consume,NULL);

    for(int x=0;x<=pthread_n;x++){
        pthread_join(p_tid[x],NULL);
    }

    sem_destroy(&shared.mutex);
    sem_destroy(&shared.full);
    sem_destroy(&shared.empty);
}

运行结果:

这里写图片描述

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

我们修改一下创建的线程数量: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的值加一。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

计算机的小粽子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值