生产者消费者问题3 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者可以拿多次,如果一次没拿到全部想要的,还可以等待生产者生产之后又去拿)

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

procon.c producer.c consumer.c
此篇程序要满足:
所有消费者都有足够产品消费。
程序不能打击来的早的消费者,就是说,消费者暂时拿不到足够产品,程序不应该剥夺他的消费权,而是应该让他等,等到货架上有足够的产品再消费。

还有有一篇我写的兄弟文章,两者相似,只是消费者有点不同-----------链接: 生产者消费者问题2 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者只能拿一次,如果一次没拿到全部想要的,没有第二次机会拿).

通过procon.c来控制producer.c和consumer.c的运行。
下图是我整个文件里面的文件,方便大家更能理解。
在这里插入图片描述

//procon.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/wait.h>  //wait()

#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("/home/ssm/shiyan2-2/pc.csv","r"); //打开文件
  fp=fopen("./pc.csv","r"); //打开文件
  if( fp == NULL ){
     printf("打开数据文件失败!\n");  
    return 0;  
  }


  char process[100],bride[100],name[100]; //读取的文件数据存放变量
  char tm[16];
  char 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(strstr(process, "生产者") !=NULL)  
                    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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/time.h>  //for gettimeofday()

#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++) {
        //找满货架
	    P(soap);
	    P(mutex);
        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], sf[j].name); 
                sf[j].name[0] = '\0'; //取出产品后,货架置空
                //V(mutex);   //释放货架区 <<<< 此处不合适,j为1,2...时,mutex信号量不能保证互斥
                //V(empty);   //发空货架消息
                break;
             }
        }
	    V(mutex);
	    V(empty);
        if(j == N) 
        {
             printf("%s找香皂失败\n",argv[1]);
        }
    }
}


//    
  
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++) {
	//找满货架
    P(towel);         //查满货架
    P(mutex);         //申请访问货架区
        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], sf[j].name); 
                sf[j].name[0] = '\0'; //取出产品后,货架置空
                //V(mutex);     //释放货架区  <<<< 此处不合适
                //V(empty);     //发空货架消息
                break;
            }
	}
	V(mutex);
	V(empty);
	if(j == N) 
        {
             printf("%s找毛巾失败\n",argv[1]);
        }
    }
}




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

return 0;   
}


//producer.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/time.h>  //for gettimeofday

#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);      //释放货架区      
               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

结果分析:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值