本文共 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的值加一。