procon.c producer.c consumer.c
还有有一篇我写的兄弟文章,两者相似,只是消费者有点不同-----------链接: 生产者消费者问题3 ---- 经典同步互斥 (3个文件,涉及共享内存,每个消费者可以拿多次,如果一次没拿到全部想要的,还可以等待生产者生产之后又去拿).
通过procon.c来控制producer.c和consumer.c的运行。
下图是我整个文件里面的文件,方便大家更能理解。
//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