代码如下:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include<string.h>
#include<sys/sem.h>
#include <sys/wait.h>
#define BUFFER_SIZE 1 /* 每次读写缓存大小,单位为字节,影响运行效率*/
#define STORE_FILE_NAME "./store" /* 源文件名*/
#define OFFSET 5 /* 复制的数据大小,单位为字节,即5个字节*/
/*
判断信号集是否存在,存在返回1,不存在返回0
*/
int sem_is_existing(int sem_id){
struct semid_ds sem_info;
if(semctl(sem_id,0,IPC_STAT,&sem_info)==-1){
perror("this sem isnt existing!!!");
return 0;
}
return 1;
}
/*
信号量初始化
sem_id:sem_get返回的信号量集标识符
n:信号量集中的编号,第一个编号为0
init_value: 设置信号量的初始值
*/
int init_sem(int sem_id, int n, int init_value) {
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
union semun sem_union;
sem_union.val = init_value;
if (semctl(sem_id, n, SETVAL, sem_union) == -1) {
perror("Initialize semaphore");
return -1;
}
return 0;
}
/*
获取该信号集束第n个信号量的可用资源数量
*/
int getResourceNum(int sem_id,int n){
return semctl(sem_id,n,GETVAL,NULL);
}
/* 从系统中删除信号量集的函数 */
int del_sem(int sem_id)
{
if (semctl(sem_id, 0, IPC_RMID,NULL) == -1)
{
perror("Delete semaphore");
return -1;
}
}
/*
P 操作函数
sem_id:信号量标识符IPC
n:信号量集中第几个信号执行-1操作
*/
int sem_p(int sem_id,int n)
{
struct sembuf sem_b;
sem_b.sem_num = n; /* 单个信号量的编号如果为0,即信号量集中的第一个信号量 */
sem_b.sem_op = -1; /* 表示P 操作 */
sem_b.sem_flg = SEM_UNDO; /* 系统自动释放将会在系统中残留的信号量*/
if (semop(sem_id, &sem_b, 1) == -1)
{
return -1;
}
return 0;
}
/*
V 操作函数
sem_id:信号量标识符IPC
n:信号量集中第几个信号执行+1操作
*/
int sem_v(int sem_id,int n)
{
struct sembuf sem_b;
sem_b.sem_num = n; /* 单个信号量的编号应该为0 */
sem_b.sem_op = 1; /* 表示V 操作 */
sem_b.sem_flg = SEM_UNDO; /* 系统自动释放将会在系统中残留的信号量*/
if (semop(sem_id, &sem_b, 1) == -1)
{
return -1;
}
return 0;
}
int main(){
pid_t pc;
int sem_mutex,sem_full,sem_empty;//定义信号量:互斥信号mutex 资源信号量empty, 可用资源信号量full
if(sem_is_existing(sem_full)==1){//该信号集已存在
del_sem(sem_full);
sem_full=semget(ftok("/",1),1,0666|IPC_CREAT);
}
else{
sem_full=semget(ftok("/",1),1,0666|IPC_CREAT);
printf("sem_full is %d\n",sem_full);
}
if(sem_is_existing(sem_empty)==1){//该信号集已存在
del_sem(sem_empty);
sem_empty=semget(ftok("/",2),1,0666|IPC_CREAT);
}
else{
sem_empty=semget(ftok("/",2),1,0666|IPC_CREAT);
printf("sem_empty is %d\n",sem_empty);
}
if(sem_is_existing(sem_mutex)==1){//该信号集已存在
del_sem(sem_mutex);
sem_mutex=semget(ftok("/",3),1,0666|IPC_CREAT);
}
else{
sem_mutex=semget(ftok("/",3),1,0666|IPC_CREAT);
printf("sem_mutex is %d\n",sem_mutex);
}
//设置互斥信号mutex的初值为1 sem_full的初值为0 sem_empty的初值为100
init_sem(sem_mutex,0,1);
init_sem(sem_full,0,0);
init_sem(sem_empty,0,100);
pc=fork();
if(pc<0){
printf("Error fork\n");
}
else if(pc==0){//子进程,消费者进程
char ch;
char space=' ';
while(1){
if(getResourceNum(sem_full,0)>0&&getResourceNum(sem_mutex,0)==1){
printf("this is consumer process,before consuming,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL));
sem_p(sem_full,0);
sem_p(sem_mutex,0);
int storeFile=open(STORE_FILE_NAME, O_RDWR);//打开提前准备好的仓库文件
if(storeFile<0){
printf("error open file!!!");
exit(1);
}
lseek(storeFile,-2,SEEK_END);
read(storeFile,&ch,1);
printf("the consumed resource is %c\n\n",ch);
lseek(storeFile,-1,SEEK_CUR);
write(storeFile,&space,1);
close(storeFile);
sem_v(sem_mutex,0);
sem_v(sem_empty,0);
printf("this is consumer process,after consuming,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL));
sleep(3);
}
}
// printf("consumer process end\n");
}
else{//父进程生产者
printf("come to father \n");
int i=0;
char str[20];
while(1){
if(getResourceNum(sem_empty,0)>0&&getResourceNum(sem_mutex,0)==1){
printf("this is producer process,before producing,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL));
sem_p(sem_empty,0);
sem_p(sem_mutex,0);
int storeFile=open(STORE_FILE_NAME, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);//打开提前准备好的仓库文件
if(storeFile<0){
printf("error open file!!!");
exit(1);
}
i=i%9;
sprintf(str,"%d\n",i);
if(write(storeFile,str,strlen(str))<0){//将数字存入store文件
printf("error write to file!!!");
close(storeFile);
exit(1);
}
sem_v(sem_full,0);
printf("the prodeced resource is %d\n\n",i);
i++;
close(storeFile);
sem_v(sem_mutex,0);
printf("this is producer process,after producing,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL));
sleep(1);
}
}
printf("producer process end\n");
}
return 0;
}
注意事项:
1.要将整形数字转换成字符型再写入文件中,因为write直接写入整型数字是以二进制的形式写入,这样的文件是不可读的,即无法打开Store文件,报错:unknowType
2.在消费者读出字符后通过将文件指针前移(-1)然后再写入' '来实现删除字符的效果,注意因为生产者写入字符时是字符+'\n'(sprintf(str,"%d\n",i));所有当消费者打开文件时要将指针从SEEK_END前移两位(-2)否则无法读出有效字符,后续删除也会出错
如有错误欢迎指出