三个经典的pv原语

1.生产者-消费者问题

  • 有m个生产者,有n个消费者,有count个缓冲区
  • 生产者在生产产品放到缓冲区;消费者从缓冲区中拿走产品消费。
  • 存在临界条件:生产者放入产品时,缓冲区满了,需要等待;缓冲区空了,消费者消费产品,需要等待
pc伪代码:
semaphore mutex;//保证缓冲区原子操作,不被中断
semaphore blank=count;//初始时,空格数最多
semaphore fillcount=0;//初始时,产品数为0

produce()
{
    while(true)
    {
        item=produceitem();//生产产品
        down(blank);//因为需要放入产品,空格数减1
            down(mutex)//保证操作缓冲区的不可中断
                putitemtobuffer(item);
            up(mutex)   
        up(fillcount);//因为放入产品,填充数加1
    }   
}

cosumer()
{
    while(true)
    {
        down(fillcount);
            down(mutex);
                item=getitemfrombuffer();
            up(mutex);
        up(blank);  
        cosumeitem(item);
    }
}
pc代码实现:
#include "common.h"

sem_t blank;
sem_t fillcount;
#define NUM 15
int buf[NUM];
static int p=0;
static int c=0;
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

void *produce1(void *arg)
{
    while(1)
    {
        sem_wait(&blank);//--操作
        pthread_mutex_lock(&mutex);
        buf[p]=rand();
        printf("produce product:%d\n",buf[p]);
        p=(p+1)%NUM;
        pthread_mutex_unlock(&mutex);
        sem_post(&fillcount);//++操作 
        sleep(1);
    }
    pthread_exit(NULL);
}

void *produce2(void *arg)
{
    while(1)
    {
        sem_wait(&blank);//--操作
        pthread_mutex_lock(&mutex);
        buf[p]=rand();
        printf("produce product:%d\n",buf[p]);
        p=(p+1)%NUM;
        pthread_mutex_unlock(&mutex);
        sem_post(&fillcount);//++操作 
        sleep(1);
    }
    pthread_exit(NULL);
}

void *consumer1(void *arg)
{
    while(1)
    {
        sem_wait(&fillcount);//--
        pthread_mutex_lock(&mutex);
        printf("consumer cosume:%d\n",buf[c]);
        c=(c+1)%NUM;
        pthread_mutex_unlock(&mutex);
        sem_post(&blank);//++
        sleep(1);
    }
    pthread_exit(NULL);
}

void *consumer2(void *arg)
{
    while(1)
    {
        sem_wait(&fillcount);//--
        pthread_mutex_lock(&mutex);
        printf("consumer cosume:%d\n",buf[c]);
        c=(c+1)%NUM;
        pthread_mutex_unlock(&mutex);
        sem_post(&blank);//++
        sleep(1);
    }
    pthread_exit(NULL);
}

int main()
{
    sem_init(&blank,0,NUM);//初始化成NUM
    sem_init(&fillcount,0,0);
    srand(time(NULL));

    pthread_t tid;
    int ret=0;
    ret=pthread_create(&tid,NULL,produce1,NULL);
    if(ret<0)
    {
        perror("pthread_create");
        exit(0);
    }
    ret=pthread_create(&tid,NULL,produce2,NULL);
    if(ret<0)
    {
        perror("pthread_create");
        exit(0);
    }
    ret=pthread_create(&tid,NULL,consumer1,NULL);
    if(ret<0)
    {
        perror("pthread_create");
        exit(0);
    }
    ret=pthread_create(&tid,NULL,consumer2,NULL);
    if(ret<0)
    {
        perror("pthread_create");
        exit(0);
    }

    while(1)
    {
        sleep(2);
    }

    return 0;
}

2、哲学家就餐问题

  • 5个哲学家,5根筷子,围坐在一个圆桌周围,平时,哲学家在思考,吃饭的时候,只有同时拿起左边和右边的筷子的哲学家才可以吃饭。
  • 临界条件:当5个哲学家都争抢着吃饭时,可能出现这样的情况,每个哲学家都拿起了左边的筷子,那么就没有一个哲学家同时拿起左边和右边的筷子
  • 如何避免出现临界条件?
  • 规定:最多只允许4个哲学家同时拿起左边的筷子
philosoper伪代码:
semaphore chopstick[5]={1};
semaphore room=4;

philosopher(int i)
{
    thinking();
    wait(room);//--操作
    wait(chopstick[i]);
    wait(chopstick[(i+1)%5]);
    eating();
    signal(chopstick[i]);//++操作
    signal(chopstick[(i+1)%5]);
    signal(room);
}
philosoper代码实现:
#include "common.h"

sem_t room;
sem_t chip[5];

void *philosopher(void *arg)
{
    int i=0;
    i=*((int *)arg);
    while(1)
    {
        printf("philosoper %d thinking\n",i);
        sem_wait(&room);
        sem_wait(&chip[i]);
        sem_wait(&chip[(i+1)%5]);
        printf("philosopher %d eating\n",i);
        sem_post(&chip[(i+1)%5]);
        sem_post(&chip[i]);
        sem_post(&room);
        sleep(2);
    }
    pthread_exit(NULL);
}

int main()
{
    //信号量初始化
    sem_init(&room,0,4);//最多只允许4个同时拿起左边的筷子
    int i=0;
    int arg[5]={0};
    for(i=0;i<5;i++)
    {
        sem_init(chip+i,0,1);//5个筷子信号量,初始化为1
        arg[i]=i;
    }

    int ret=0;
    pthread_t tid;
    for(i=0;i<5;i++)
    {
        ret=pthread_create(&tid,NULL,philosopher,(void *)&arg[i]);
        if(ret<0)
        {
            perror("pthread_create");
            exit(0);
        }
    }

#if 0
    while(1)
    {
        sleep(2);
    }   
#endif

    pthread_join(tid,NULL);

    return 0;
}

3.读者-写者问题

  • m个读者在读文件,n个写者在写文件。
  • 规定:读者可以同时读文件;写者不可以同时写文件;也不可以同时读文件和写文件
  • 为了实现读者-写者问题,需要定义2把锁:读锁和写锁
rw伪代码:
semaphore rmutex;
semaphore wmutex;

//写者
down(wmutex)
writing
up(wmutex)

//读者
down(rmutex)
if(readcount==0)
{
    down(wmutex)
}
readcount++
up(rmutex)

reading

down(rmutex)
readcount--
if(readcount==0)
{
    up(wmutex)
}
up(rmutex)
rw代码实现:
#include "common.h"

sem_t rmutex;
sem_t wmutex;
int wnum=0;
int rnum=0;
int buf[3]={0};

void read()
{

}

void write()
{   
    wnum++;
    int i=(wnum%3)+1printf("%d号写者在写",i);
    sleep(2);
}

void *reader(void *arg)
{
    while(1)
    {
        sem_wait(&rmutex);
        if(rnum==0)
        {
            sem_wait(&wmutex);
        }
        rnum++;
        sem_post(&rmutex);

        read();

        sem_wait(&rmutex);
        rnum--;
        if(rnum==0)
        {
            sem_post(&wmutex);
        }
        sem_post(&rmutex);
    }
    pthread_exit(NULL);
}

void *writer(void *arg)
{
    while(1)
    {
        sem_wait(&wmutex);
        write();
        sem_post(&wmutex);
    }
    pthread_exit(NULL);
}

int main()
{
    sem_init(&rmutex,0,1);
    sem_init(&wmutex,0,1);

    pthread_t tid;
    int ret=0,i;
    for(i=0;i<3;i++)
    {
        pthread_create(&tid,NULL,writer,NULL);
        if(ret<0)
        {
            perror("pthread_create");
            exit(0);
        }
    }
    for(i=0;i<5;i++)
    {
        pthread_create(&tid,NULL,reader,NULL);
        if(ret<0)
        {
            perror("pthread_create");
            exit(0);
        }
    }

    pthread_join(tid,NULL);

    return 0;
}
  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值