这是我的操作系统实验课的实验之一,实验要求“实现生产者和消费者程序”。
老师给了我们示例程序,要求我们自己修改调试。程序代码如下,已经在本地linux系统上能够正确运行。
p是模拟生产者,c是模拟消费者,q是退出
但是有一点,如果不是用q退出而是中途用ctrl+c的话,再次运行程序就是显示"segment:File exists"
解决的方法是:
ipcs -s 显示已存在的信号量
ipcrm -s 删除指定信号量
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/sem.h>
#include "shmpc.h"
/*
********************************************************************************
* Name: main
* Description: entry point
********************************************************************************
*/
//var used to shared memory
int shmid;
void *myshm;
struct myshm_st *buf;
//var used to semaphore
int semid;
//common var
int i,n;
void producer()
{
printf ( "Create a Producer Process Success,%d\n",getpid());
//attach share memory
myshm=shmat(shmid,NULL,0);
if(myshm==(void *)-1)
{
perror("shmat");
exit(-1);
}
buf=(struct myshm_st *)myshm;
//produe a product
for(n=0;n<NSIZE;n++)
{
while(buf->m_count==BUFSIZE)
{
printf("[%d/P/%d]:Blocked!\n",getpid(),n);
sleep(5);
}
//P
struct sembuf action;
action.sem_num=0;
action.sem_op=-1;
action.sem_flg=SEM_UNDO;
if(semop(semid,&action,1)==-1)
{
perror("semop");
exit(0);
}
buf->m_count++;
buf->m_buf[buf->m_in]='A';
sleep(1);
buf->m_in=(buf->m_in+1)%BUFSIZE;
printf("[%d/P/%d]:",getpid(),n);
for(i=0;i<10;i++)
{
if(buf->m_buf[i]=='A')
printf("|A");
else
printf("| ");
}
printf("|\n");
//V
action.sem_op=1;
if(semop(semid,&action,1)==-1)
{
perror("semop");
exit(0);
}
sleep(DELT);
}
if(shmdt(myshm)==-1)
perror("shmdt");
exit(0);
}
void consumer()
{
printf ( "Create a Consumer Process Success,%d\n",getpid());
//attach share memory
myshm=shmat(shmid,NULL,0);
if(myshm==(void *)-1)
{
perror("shmat");
exit(-1);
}
buf=(struct myshm_st *)myshm;
//consum a product
for(n=0;n<NSIZE;n++)
{
while(buf->m_count==0)
{
printf("[%d/C/%d]:Blocked!\n",getpid(),n);
sleep(5);
}
//P
struct sembuf action;
action.sem_num=0;
action.sem_op=-1;
action.sem_flg=SEM_UNDO;
if(semop(semid,&action,1)==-1)
{
perror("semop");
exit(0);
}
buf->m_count--;
buf->m_buf[buf->m_out]=' ';
buf->m_out=(buf->m_out+1)%BUFSIZE;
printf("[%d/C/%d]:",getpid(),n);
for(i=0;i<10;i++)
{
if(buf->m_buf[i]=='A')
printf("|A");
else
printf("| ");
}
printf("|\n");
//V
action.sem_op=1;
if(semop(semid,&action,1)==-1)
{
perror("semop");
exit(0);
}
sleep(DELT);
}
if(shmdt(myshm)==-1)
perror("shmdt");
exit(0);
}
int main(int argc, char *argv[])
{
char t;
int ppid,cpid;
//create a shared memery
printf("Begin...\n");
shmid=shmget(MYKEY,sizeof(struct myshm_st),IPC_CREAT|0770);
if( shmid==-1 )
{
perror("shmget");
exit(-1);
}
//attach shared memory
myshm=shmat(shmid,NULL,0);
if(myshm==(void *)-1)
{
perror("shmat");
exit(-1);
}
//init shared memory
buf=(struct myshm_st *)myshm;
buf->m_count=0;
buf->m_in=0;
buf->m_out=0;
//create a semaphore
semid=semget(MYKEY,1,IPC_CREAT|IPC_EXCL|0770);
if( semid==-1 )
{
perror("semget");
exit(0);
}
union semun init_val;
init_val.val=1;
if( semctl(semid,0,SETVAL,init_val )==-1)
{
perror("semctl");
exit(0);
}
for(;;)
{
t=getchar();
switch ( t )
{
case 'p' :
//create a producer process
ppid=fork();
if( ppid==0 )
{
producer();
}
break;
case 'c':
cpid=fork();
if( cpid==0 )
{
consumer();
}
break;
case 's':
//please add stat code here
case 'q':
if(shmdt(myshm)==-1)
perror("shmdt");
if(shmctl(shmid,IPC_RMID,0)==-1)
perror("shmctl");
if(semctl(semid,1,IPC_RMID,NULL)==-1)
perror("semctl");
exit(0);
}
}
}
shampc.h
/*
* Description limited buffer
*/
#define BUFSIZE 10
#define MYKEY 9000
#define MUTEX 9001
#define FULL 9002
#define EMPTY 9003
#define NSIZE 5 //number of item each child
#define DELT 1 //interval between two item
struct myshm_st
{
int m_count;
int m_in;
int m_out;
char m_buf[BUFSIZE];
};
union semun
{
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
};