问题描述:假设在生产者与消费者之间有一个大小为n的缓冲区,生产者要向缓冲区里存放东西,消费者要从中取出东西,该如何控制二者能够不冲突的运转。
解决方法:当缓冲区满时生产者不可再放入,当缓冲区空时消费者不可再取出。
当有生产者向缓冲区存放东西时,其他生产者不可以再向缓冲区输出;当有消费者从缓冲区取出东西时,其他消费者不可以从缓冲区取出东西。
具体实现:1.通过两个信号量s1,s2来控制当前是生产者还是消费者占用缓冲区。
2.通过互斥锁,来决定具体为哪一个生产者向缓冲区生产东西。(消费者类似)
图示及解释:
首先,一个大小为n的缓冲区,分别定义两个信号量s1 = n,s2 = 0,如果s1为0则消费者不能从缓冲区中取出东西(s2为0类似)。这样我们对应的p、v操作就能确定
接着,当生产者执行p操作,所有的生产者线程都会抢占那个往缓冲区写入的机会,这时当有一个生产者线程抢到这个机会就立即上锁,防止别的线程打扰,写完、开锁、v操作、结束。
这里有一个需要注意的点:究竟是先p操作还是先上锁?
想想如果先上锁会怎样->假如生产者lock(上锁),这时只能紧接着执行p操作,然后要向缓冲区写入内容,但是如果缓冲区这时候是满的呢,就会无法写入,同时已经lock操作了,消费者也没机会从缓冲区取出东西,就会发生死锁!
理解以上内容代码即可实现:
//生产者消费者问题
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
#include <time.h>
#define BUFF_MAX 30 //缓冲区大小
pthread_mutex_t mutex; //保证互斥访问缓冲区
sem_t sem_empty;
sem_t sem_full;
int in = 0; //表示生产
int out = 0;
char buff[BUFF_MAX];
void* pro_fun(void* arg)
{
for(int i = 0; i < 30; i++)
{
sem_wait(&sem_empty); //p(s1)
pthread_mutex_lock(&mutex); //lock
buff[in] = rand() % 100; //write
printf("post:%d producer:%d\n", in, buff[in]);
in = (in + 1) % BUFF_MAX; //移动in指针
pthread_mutex_unlock(&mutex); //unlock
sem_post(&sem_full); //v(s2)
}
}
void* con_fun(void* arg)
{
for(int i = 0; i < 20; i++)
{
sem_wait(&sem_full); //p(s2)
pthread_mutex_lock(&mutex); //lock
printf("---post%d consumer:%d\n", out, buff[out]);//read
out = (out + 1) % BUFF_MAX;
pthread_mutex_unlock(&mutex); //unlock
sem_post(&sem_empty); //v(s2)
}
}
int main()
{
sem_init(&sem_empty, 0, BUFF_MAX);
sem_init(&sem_full, 0, 0);
pthread_mutex_init(&mutex, NULL);
pthread_t pro_id[2];
for(int i = 0; i < 2; i++)
{
pthread_create(&pro_id[i], NULL, pro_fun, NULL);//启动两个生产者
}
pthread_t con_id[3];
for(int i = 0; i <3; i++)
{
pthread_create(&con_id[i], NULL, con_fun, NULL);//启动三个消费者
}
for(int i = 0; i < 2; i++)
{
pthread_join(pro_id[i], NULL);
}
for(int i = 0; i < 3; i++)
{
pthread_join(con_id[i], NULL);
}
pthread_mutex_destroy(&mutex);
sem_destroy(&sem_empty);
sem_destroy(&sem_full);
exit(0);
}
运行结果:
一点理解:生产者与消费者并不是什么从属关系,不是生产然后消费,生产然后消费。
而是当有机会去生产或者有机会去消费的时候,就会抓紧机会去做该做的事,这其实是与线程的并发性有关,各个线程会去争抢资源,而我们要做的就是处理好这种竞争关系,避免陷入死锁这种情况。
其实人生也是不必太过于执着某个东西,一切自有天意,正确的人或事都会在正确的时间来到你身边,撞过南墙,就别再执着于南墙了。