Bootstrap

PV操作、生产者消费者问题、读者写者问题、睡眠理发师问题

P、V操作原语定义:

  • P原语操作: 信号量减1,若此时信号仍然大于等于0,则进程继续执行; 若此时信号量小于零,则进程阻塞,在队列中排队,然后等待。
  • V原语操作:信号量加1,若此时信号量大于零,则进程继续执行,若此时信号量小于或等于零,则唤醒阻塞在此信号量的进程,然后执行该V操作的进程继续执行。

生产者消费者问题

  • 在缓冲区为空时,消费者不能再进行消费
  • 在缓冲区为满时,生产者不能再进行生产
  • 在一个线程进行生产或消费时,其余线程不能再进行生产或消费等操作
  • 即保持线程间的同步 注意条件变量与互斥锁的顺序

伪代码描述

item B[k];
semphore empty;
empty=k;
semphore full;
full=0;
semphore mutex;
metax=1;
int in=0; //写指针
int out=0;//读指针
cobegin//并发结束
process producer_i(  )               process consumer_j(  )
{                                    {
      while(true)                          while(true) 
      {                                    {
      produce();//生产数据                    p(full);
      p(empty);                              p(mutex);
      p(mutex);                              take from B[out];
      append to B[in];//将数据放入缓冲区       out=(out+1)%k  //从缓冲区中取出数据
      in=(in+1)%k                            v(mutex);   
      v(mutex);                              v(empty); 
        v(full);                             consume();//消费数据
      }                                     }
}                                    }   
coend//并发开始

c语言代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>
#define Maxbuf 10
#define TimesOfOp 10
#define true 1
#define false 0
//定义循环缓冲队列及其操作
struct Circlebuf
{
	int read;
	int write;
	int buf[Maxbuf];
}circlebuf;

sem_t mutex;
sem_t empty;
sem_t full;
int product_id = 0;   //生产者id
int prochase_id = 0; //消费者id

void writeCirclebuf(struct Circlebuf *circlebuf,int *value)
//向缓冲区中写一个值
{
	circlebuf->buf[circlebuf->write]=(*value);
	circlebuf->write=(circlebuf->write+1)%Maxbuf;
}

int readCirclebuf(struct Circlebuf *circlebuf)
{
	int value=0;
	value=circlebuf->buf[circlebuf->read];
	circlebuf->buf[circlebuf->read]=0;
	circlebuf->read=(circlebuf->read+1)%Maxbuf;
	return value;
}

void OutCirclebuf(struct Circlebuf *circlebuf)
{
	int i;
	printf("现存:");
	for(i=0;i<Maxbuf;i++)
	{
		printf("%d ",circlebuf->buf[i]);
	}
	printf("\n");
}

void sigend(int sig)
{
	exit(0);
}

void *productThread(void *i)
{
int id=product_id++;
	int *n=(int *)i;
	int t=TimesOfOp;
	while(t--)
	{
		sem_wait(&empty);
		sem_wait(&mutex);
		writeCirclebuf(&circlebuf,n);
		printf("生产者 %d 写入= %d. \n",id,*n);
		OutCirclebuf(&circlebuf);
		sem_post(&mutex);
		sem_post(&full);
	}
}

void *consumerThread(void *i)
{
int id=prochase_id++;
	int *n=(int *)i;
	int value=0;
	int t=TimesOfOp;
	while(t--)
	{
		sem_wait(&full);
		sem_wait(&mutex);
		value=readCirclebuf(&circlebuf);
		printf("消费者 %d 取走= %d. \n",id,*n);
		OutCirclebuf(&circlebuf);
		sem_post(&mutex);
		sem_post(&empty);
	}

}

int main()
{
	int i;
	int ConsNum=0,ProdNum=0,ret;
	pthread_t cpid,ppid;
	sem_init(&mutex,0,1);
	sem_init(&empty,0,Maxbuf);
	
	sem_init(&full,0,0);
	signal(SIGINT,sigend);
	signal(SIGTERM,sigend);
	//初始化循环缓冲队列
	circlebuf.read=circlebuf.write=0;
	for(i=0;i<Maxbuf;i++)
	{
		circlebuf.buf[i]=0;
	}
	printf("输入生产者的数目:");
	scanf("%d",&ProdNum);
	int *pro=(int *)malloc(ProdNum*sizeof(int));
	printf("输入消费者的数目:");
	scanf("%d",&ConsNum);
	int *con=(int *)malloc(ProdNum*sizeof(int));
	for(i=1;i<ConsNum;i++)
	{
		cpid=i;
		con[i-1]=i;
		ret=pthread_create(&cpid,NULL,consumerThread,(void *)&con[i-1]);
		if(ret!=0)
		{
			printf("Create thread error");
			exit(1);
		}
	}
	for(i=1;i<=ProdNum;i++)
	{
		ppid=i+100;
		pro[i-1]=i;
		ret=pthread_create(&ppid,NULL,productThread,(void *)&pro[i-1]);
		if(ret!=0)
		{
			printf("Create thread error");
			exit(1);
		}
	}
	sleep(1);
	sem_destroy(&mutex);
	sem_destroy(&empty);
	sem_destroy(&full);
	pthread_exit(NULL);
}

读者写者问题

  • 允许多个读者可以同时对文件执行读操作;
  • 只允许一个写者往文件中写信息;
  • 任一写者在完成写操作之前不允许其他读者或写者工作;
  • 写者执行写操作前,应让已有的读者和写者全部退出。
  • 也就是说,读进程不排斥其他读进程,而写进程需要排斥其他所有进程,包括读进程和写进程。
    伪代码
    在这里插入图片描述
int readcount;
semphore wirteblock,mutex;
wirte=1;
mutex=1;
readcount=0;
cobegin
process reader( )                      process wirter()             
{                                      {
     P(mutex)                                 P(wirteblock)
     readcount++;                              {写操作}    
   //如果是第一个读者,p(wirteblock),防止写者进行写操作                                           v(wirteblock)
     if(readcount==1) p(wirteblock)           V(wirteblock)
     V(mutex)                           }
     {读操作}                           
     P(mutex)
     readcount--;
   //如果是最后一个读者,v(wirteblock),允许写者进行写操作   
     if(readcount==0) v(writeblock)
     V(mutex)
}
coend

在这里插入图片描述

睡眠理发师问题

  • 有一个理发师的椅子,和n个顾客的椅子 如果有顾客在椅子上等,那么理发师为他剪发,否则理发师就在自己的椅子上睡觉。
  • 如果理发师在熟睡,那么顾客会叫醒理发师,否则顾客会看有没有空椅子,有的话,他坐下等,否则,他将离开理发店。
    伪代码
semphore mutex,consumer,barber;
int chair,waiting;
mutex=1;
consumer=0;
barber=1;
chair=N;
waiting=0;
cobegin
process barber()
{
   while(true)
   {
      P(consumer);
      P(mutex);
      waiting--;
      V(barber);
      V(mutex);
      cut_hair();
   }
}
process consumer()
{
   P(mutex)
   if(waiting<chair)
   {
     waiting++;
     V(consumer);
     V(mutex);
     P(barber);
     get_haircut();
   }
   else V(mutex)
}
coend
;