生产者消费者问题2 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者只能拿一次,如果一次没拿到全部想要的,没有第二次机会拿)

生产者消费者问题,三个.c文件实现

procon.c producer.c consumer.c

还有有一篇我写的兄弟文章,两者相似,只是消费者有点不同-----------链接: 生产者消费者问题3 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者可以拿多次,如果一次没拿到全部想要的,还可以等待生产者生产之后又去拿).

通过procon.c来控制producer.c和consumer.c的运行。
下图是我整个文件里面的文件,方便大家更能理解。
生产者消费者问题2 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者只能拿一次,如果一次没拿到全部想要的,没有第二次机会拿)_第1张图片

//procon.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include

#define M_KEY  5201
#define E_KEY  5207
#define T_KEY  5208
#define S_KEY  5209
int mutex,empty,towel,soap;  //声明信号量

#define N 32   //32个货架
#define MAX_PROCESSES 32 //最大进程数

#define SHMKEY 2020   //共享区关键字

 
int main(int argc,char **argv)
{ 
    int i, status;
    pid_t pid, wpid;


int shmid;  //共享区标识符
char *addr;//共享内存的首地址

//创建共享内存
  shmid = shmget(SHMKEY,1024,0660|IPC_CREAT);
  addr = (char *)shmat(shmid,0,0);
  memset(addr,0,1024); //共享区清0

  FILE *fp; 
  fp=fopen("./pc.csv","r"); //打开文件
  if( fp == NULL ){
     printf("打开数据文件失败!\n");  
    return 0;  
  }


  char tm[16],process[100],bride[100],name[100],count[16]; //读取的文件数据存放变量

  
    mutex=semget(M_KEY,1,IPC_CREAT|0660);//创建信号量
    semctl(mutex,0,SETVAL,1); //初值1
    
    empty=semget(E_KEY,1,IPC_CREAT|0660);//创建空信号量
    semctl(empty,0,SETVAL,N); //初值N
    
    towel=semget(T_KEY,1,IPC_CREAT|0660);//创建满信号量
    semctl(towel,0,SETVAL,0); //初值0

    soap=semget(S_KEY,1,IPC_CREAT|0660);//创建满信号量
    semctl(soap,0,SETVAL,0); //初值0

  
//////////////////////////////读文件创建相应进程/////////////////////////////////////////////////
          while( !feof(fp) )
          { 
          
	  if (fscanf( fp, " %[^,], %[^,], %[^,], %[^,], %s%*c ", process, tm, bride, name, count ) != 5) break;
	   
	     printf( "%s %s %s %s %s\n", process, tm, bride, name, count ); 
            pid=fork();
            if(pid==0){
                //sprintf(num, "%d", i);
                if(strncmp (process, "生产者", 6) == 0)  
                    execlp("./producer", tm, process, bride, name, count, NULL); //执行producer程序
                         
                else execlp("./consumer", tm, process, bride, name, count, NULL);//执行consumer程序		     
                exit(0);
               }
	  }  

  fclose( fp );  

          if(pid>0) {
		while ((wpid = wait(&status)) > 0); //等待所有子进程结束
		printf("所有进程都已结束。\n");
		//结束之前:扫尾工作
		shmdt(addr); //断开共享区
                shmctl(shmid,IPC_RMID, 0); //删除共享区

                semctl(mutex, 0, IPC_RMID); //删除信号量
	        semctl(empty, 0, IPC_RMID); //删除信号量
	        semctl(towel, 0, IPC_RMID); //删除信号量
                semctl(soap, 0, IPC_RMID); //删除信号量
	  }
	         
  return 0;  
}  

//consumer.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include

#define M_KEY  5201
#define E_KEY  5207
#define T_KEY  5208
#define S_KEY  5209
int mutex,empty,towel,soap;  //声明信号量

#define N  32    //最大货架数
#define MAX_PROCESSES  32  //最大进程数

#define SHMKEY 2020   //共享区关键字

//货架结构体
typedef struct Shelf_t{
    char name[32];//产品名,一个utf-8汉字占3字节
}Shelf;


int P(int sid) //P操作
{
    struct sembuf sb={0,-1,0};
    return semop(sid, &sb, 1);
}
 
int V(int sid) //V操作
{
    struct sembuf sb={0,1,0};
    return semop(sid, &sb, 1);
};



int main(int argc,char **argv)
{
    int shmid; //共享区标识符
    char *addr; //共享区地址
    Shelf *sf; //货架指针
    int i,j;
    int start;

    mutex=semget(M_KEY,1,IPC_CREAT|0660);//创建信号量
   // semctl(mutex,0,SETVAL,1); //初值1
    
    empty=semget(E_KEY,1,IPC_CREAT|0660);//创建空信号量
   // semctl(empty,0,SETVAL,N); //初值N
    
    towel=semget(T_KEY,1,IPC_CREAT|0660);//创建满信号量
   // semctl(towel,0,SETVAL,0); //初值0

    soap=semget(S_KEY,1,IPC_CREAT|0660);//创建满信号量
  //  semctl(soap,0,SETVAL,0); //初值0

    struct timeval tv,tv0;
    gettimeofday(&tv0, NULL);
    tv.tv_sec/=10; tv.tv_sec*=10; //初始时间tv0,去个位秒数

    //创建共享区
    shmid = shmget(SHMKEY,1024,IPC_CREAT|0660);
    addr = (char*)shmat(shmid,0,0);
    sf = (Shelf *)addr;
 
    start=atoi(argv[0]); //开始时间

//---------------------互斥访问货架------------------------------------------------------------------------

if(strcmp(argv[3],"香皂") == 0) {
     P(soap);            //查满货架
	P(mutex);         //申请访问货架区
      printf("\n%s到达, 计划消费%s %d个\n\n",argv[1],argv[3],atoi(argv[4])); 

   for(i = 0;i < atoi(argv[4]);i++) {
	//找满货架

       for(j = 0;j < N;j++) {
           if(strstr(sf[j].name,"香皂") != NULL) {
               gettimeofday(&tv, NULL);
               tv.tv_sec-=tv0.tv_sec;
               printf("取货时间%d.%d:  %s, 货架号:%d  拿取品牌:%s  名称:%s\n",(int)tv.tv_sec, (int)tv.tv_usec, argv[1], j, argv[2], argv[3]); 
               sf[j].name[0] = '\0'; //取出产品后,货架置空
                  //    V(mutex);     //释放货架区   <<<< 此处不合适,j为1,2...时,mutex信号量不能保证互斥
                 V(empty);       //发空货架消息
               break;
           }
	}
      
	if(j == N) 
          {
             printf("%s找香皂失败\n",argv[1]);
          }
    }
V(mutex);
}


//////////////////////////////////////////////////////////////////////////////////////////////////    
  
if(strcmp(argv[3],"毛巾") == 0) {
	 P(towel);            //查满货架
             P(mutex);         //申请访问货架区
      printf("\n%s到达, 计划消费%s %d个\n\n",argv[1],argv[3],atoi(argv[4])); 

   for(i = 0;i < atoi(argv[4]);i++) {
	//找满货架

       for(j = 0;j < N;j++) {
           if(strstr(sf[j].name,"毛巾") != NULL) {
               gettimeofday(&tv, NULL);
               tv.tv_sec-=tv0.tv_sec;
               printf("取货时间%d.%d:  %s, 货架号:%d  拿取品牌:%s  名称:%s\n",(int)tv.tv_sec, (int)tv.tv_usec, argv[1], j, argv[2], argv[3]); 
               sf[j].name[0] = '\0'; //取出产品后,货架置空
                   //   V(mutex);     //释放货架区  <<<< 此处不合适,j为1,2...时,mutex信号量不能保证互斥
                 V(empty);       //发空货架消息
               break;
           }
	}

	if(j == N) 
          {
             printf("%s找毛巾失败\n",argv[1]);
          }
    }
V(mutex);
}




shmdt(addr); //断开共享区

return 0;   
}

//producer.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include

#define M_KEY  5201
#define E_KEY  5207
#define T_KEY  5208
#define S_KEY  5209
int mutex,empty,towel,soap;  //声明信号量

#define N  32    //最大货架数
#define MAX_PROCESSES  32  //最大进程数

#define SHMKEY 2020   //共享区关键字

//货架结构体
typedef struct Shelf_t{
    char name[32];//产品名,一个utf-8汉字占3字节
}Shelf;


int P(int sid) //P操作
{
    struct sembuf sb={0,-1,0};
    return semop(sid, &sb, 1);
}
 
int V(int sid) //V操作
{
    struct sembuf sb={0,1,0};
    return semop(sid, &sb, 1);
};



int main(int argc,char **argv)
{
    int shmid; //共享区标识符
    char *addr; //共享区地址
    Shelf *sf; //货架指针
    int i,j;
    int start;

    mutex=semget(M_KEY,1,IPC_CREAT|0660);//创建信号量
  //  semctl(mutex,0,SETVAL,1); //初值1
    
    empty=semget(E_KEY,1,IPC_CREAT|0660);//创建空信号量
  //  semctl(empty,0,SETVAL,N); //初值N
    
    towel=semget(T_KEY,1,IPC_CREAT|0660);//创建满信号量
  //  semctl(towel,0,SETVAL,0); //初值0

    soap=semget(S_KEY,1,IPC_CREAT|0660);//创建满信号量
 //   semctl(soap,0,SETVAL,0); //初值0


    struct timeval tv,tv0;
    gettimeofday(&tv0, NULL);
    tv.tv_sec/=10; tv.tv_sec*=10; //初始时间tv0,去个位秒数

    //创建共享区
    shmid = shmget(SHMKEY,1024,IPC_CREAT|0660);
    addr = (char*)shmat(shmid,0,0);
    sf = (Shelf *)addr;
 
    start=atoi(argv[0]); //开始时间
    sleep(start); //挨过开始时间

//-------------------------------------------互斥访问货架-------------------------------------------------------------------

P(empty);       //查空货架
   P(mutex);      //申请访问货架区

  printf("\n%s到达, 计划生产%s %d个\n\n",argv[1],argv[3],atoi(argv[4])); 
   
///////////////////////////////////////////////////////////// 
 if(strcmp(argv[3],"毛巾") == 0) {
   for(i = 0;i < atoi(argv[4]);i++) {
	//找空货架
       for(j = 0;j < N;j++) {
           if(sf[j].name[0] == '\0') {
               gettimeofday(&tv, NULL);
               tv.tv_sec-=tv0.tv_sec;
               strcpy(sf[j].name,argv[3]); //放入货架
               printf("%d.%d: %s  货架号:%d  放置品牌:%s  名称:%s\n",(int)tv.tv_sec,(int)tv.tv_usec, argv[1], j, argv[2], argv[3]); 
                 //V(mutex);      //释放货架区    <<<<此处有漏洞,j为1,2,...时不能保证互斥  
               V(towel); //空毛巾区
               break;
           }
	}
	if(j == N) 
	{
            printf("%s找空货架失败\n",argv[1]);
        }
    }
}


else if(strcmp(argv[3],"香皂") == 0) {
   for(i = 0;i < atoi(argv[4]);i++) {
	//找空货架
       for(j = 0;j < N;j++) {
          
           if(sf[j].name[0] == '\0') {
               gettimeofday(&tv, NULL);
               tv.tv_sec-=tv0.tv_sec;
               strcpy(sf[j].name,argv[3]); //放入货架
               printf("%d.%d: %s  货架号:%d  放置品牌:%s  名称:%s\n",(int)tv.tv_sec,(int)tv.tv_usec, argv[1], j, argv[2], argv[3]); 
                  //V(mutex);      //释放货架区      <<<<此处有漏洞,j为1,2,...时不能保证互斥
               V(soap); //空香皂区
               break;
           }
	}
	if(j == N) 
	{
	    printf("%s找空货架失败\n",argv[1]);
        }
    }
}

V(mutex);      //释放货架区      
////////////////////////////////////////////////////////////

shmdt(addr); //断开共享区


return 0;   
}






文件名为Makefile,功能:简便的一次性编译多个.c文件
使用方法:命令行输入 make 即可

//Makefile

#Makjfile1:wq
target: producer consumer procon
producer: producer.c
	gcc -pthread producer.c -o producer
consumer: consumer.c
	gcc -pthread consumer.c -o consumer
procon: procon.c
	gcc -pthread procon.c -o procon
clean: producer consumer procon
	rm -f producer consumer procon

结果分析:
生产者消费者问题2 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者只能拿一次,如果一次没拿到全部想要的,没有第二次机会拿)_第2张图片生产者消费者问题2 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者只能拿一次,如果一次没拿到全部想要的,没有第二次机会拿)_第3张图片
生产者消费者问题2 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者只能拿一次,如果一次没拿到全部想要的,没有第二次机会拿)_第4张图片

生产者消费者问题2 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者只能拿一次,如果一次没拿到全部想要的,没有第二次机会拿)_第5张图片

你可能感兴趣的:(操作系统学习之路)