作业要求:
![](https://img-blog.csdnimg.cn/a49c3c939fd8459aa42690cb7c1c4719.png)
sem.h内容:
#ifndef _SEM_H_
#define _SEM_H_
//声明一个创建信号灯集并初始化函数
int init_sem(int semnum);//semnum 灯的个数
//声明一个P操作函数
int P(int semid,int semno);//semno 灯的编号
//声明一个V操作函数
int V(int semid,int semno);
//声明一个删除信号灯的函数
int del_sem(int semid);
#endif
sem.c内容:
#include<myhead.h>
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
//自定义初始化信号灯函数
int set_semno_value(int semid, int semno, int semval)
{
//定义共用体
union semun us;
us.val = semval;
//调用semctl对灯进行初始化
if(semctl(semid, semno, SETVAL, us) == -1)
{
perror("semctl error");
return -1;
}
return 0;
}
//创建信号灯集并初始化函数的定义
int init_sem(int semnum)
{
//1、创建key值
key_t key;
if((key = ftok("/", 't')) ==-1)
{
perror("ftok error");
return -1;
}
//2、创建信号灯集
int semid;
if((semid = semget(key, semnum, IPC_CREAT|IPC_EXCL|0664)) == -1)
{
if(errno == EEXIST)
{
//表明信号灯集已经存在,直接打开即可
semid = semget(key, semnum, IPC_CREAT|0664);
return semid; //将信号灯集打开后,直接将信号灯集id返回
}else
{
perror("semget error");
}
return -1;
}
//3、给信号灯集进行初始化
for(int i=0; i<semnum; i++)
{
if(i == 0)
{
//设置信号灯的初始值
//参数1:信号灯集
//参数2:要操作的信号灯编号
//参数3:要设置的值
set_semno_value(semid, i, 1);
}else
{
set_semno_value(semid, i, 0);
}
}
return semid;
}
//P操作函数的定义
int P(int semid, int semno)
{
//定义一个操作结构体变量
struct sembuf buf;
buf.sem_num = semno; //要操作的信号灯编号
buf.sem_op = -1; //表示要进行申请资源
buf.sem_flg = 0; //表示阻塞申请资源
if(semop(semid, &buf, 1) == -1)
{
perror("P error");
return -1;
}
return 0;
}
//V函数的定义
int V(int semid, int semno)
{
//定义一个操作结构体变量
struct sembuf buf;
buf.sem_num = semno; //要操作的信号灯编号
buf.sem_op = 1; //表示要进行申请资源
buf.sem_flg = 0; //表示阻塞申请资源
if(semop(semid, &buf, 1) == -1)
{
perror("V error");
return -1;
}
return 0;
}
//删除信号灯集的函数的定义
int del_sem(int semid)
{
//删除信号灯集
if(semctl(semid, 0, IPC_RMID, 0) == -1)
{
perror("delete error");
return -1;
}
return 0;
}
用户一函数代码及截图:
#include<myhead.h>
#include"sem.h"
int main(int argc, const char *argv[])
{
//11、打开信号灯集
int semid = init_sem(4);
//1、创建key值
key_t key;
if((key = ftok("/", 'k')) == -1)
{
perror("ftok error");
return -1;
}
//2、创建共享内存
int shmid;
if((shmid = shmget(key, 4096, IPC_CREAT|0664)) == -1)
{
perror("shmget error");
return -1;
}
//3、映射内存
char *addr = NULL; //指向共享内存段
if((addr = shmat(shmid, NULL, 0)) == (void*)-1)
{
perror("shmat error");
return -1;
}
//定义一个进程号,并创建一个子进程
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("fork error");
return -1;
}else if(pid == 0)
{
//子进程,在接收到2号信号灯的资源后,再读取共享内存中的数据
while(1)
{
//等待2号信号灯的资源
P(semid,2);
//读取共享内存中的数据
printf("读取的数据为%s\n",addr);
//释放3号信号灯的资源
V(semid,3);
//设定循环退出条件
if(strcmp(addr,"quit") == 0)
{
break;
}
}
//退出子进程
exit(EXIT_SUCCESS);
}else{
//父进程,在接收到0号信号灯的资源后,再向共享内存中写入数据
while(1)
{
//等待0号信号灯资源
P(semid,0);
//向共享内存中写入数据
fgets(addr,4096,stdin);
addr[strlen(addr)-1] = '\0';
//释放1号灯资源
V(semid,1);
//设定循环退出条件
if(strcmp(addr,"quit") == 0)
{
break;
}
}
//回收子进程资源
wait(NULL);
}
//5、取消映射
if(shmdt(addr) == -1)
{
perror("shmdt error");
return -1;
}
return 0;
}
跑【
![](https://img-blog.csdnimg.cn/1b01f29941ef4594aa5be5e8d8b912c0.png)
用户二函数代码及截图:
#include<myhead.h>
#include"sem.h"
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
int main(int argc, const char *argv[])
{
//11、创建信号灯集
int semid = init_sem(2);
//1、创建key值
key_t key;
if((key = ftok("/", 'k')) == -1)
{
perror("ftok error");
return -1;
}
//2、创建共享内存
int shmid;
if((shmid = shmget(key, 4096, IPC_CREAT|0664)) == -1)
{
perror("shmget error");
return -1;
}
//3、映射内存
char *addr = NULL; //指向共享内存段
if((addr = shmat(shmid, NULL, 0)) == (void*)-1)
{
perror("shmat error");
return -1;
}
//定义一个进程号,并创建一个子进程
pid_t pid;
pid = fork();
if(pid < 0)
{
perror("fork error");
return -1;
}else if(pid == 0)
{
//子进程,在接收到3号信号灯的资源后,再向共享内存中写入数据
//将3号灯的资源初始化为1
union semun us;
us.val = 1;
semctl(semid,3,SETVAL,us);
while(1)
{
//等待3号信号灯资源
P(semid,3);
//向共享内存中写入数据
fgets(addr,4096,stdin);
addr[strlen(addr)-1] = '\0';
//释放2号信号灯的资源
V(semid,2);
//设定循环退出条件
if(strcmp(addr,"quit") == 0)
{
break;
}
}
//退出子进程
exit(EXIT_SUCCESS);
}else
{
//父进程,在接收到1号信号灯资源后,再从共享内存中读取数据
while(1)
{
//等待1号灯资源
P(semid,1);
//读取共享内存中的数据
printf("读取的数据为%s\n",addr);
//释放0号灯资源
V(semid,0);
//设定循环退出条件
if(strcmp(addr,"quit") == 0)
{
break;
}
}
//回收子进程资源
wait(NULL);
}
//5、取消映射
if(shmdt(addr) == -1)
{
perror("shmdt error");
return -1;
}
//6、删除共享内存
if(shmctl(shmid, IPC_RMID, NULL) ==-1)
{
perror("shmctl error");
return -1;
}
//44、删除信号灯集
del_sem(semid);
return 0;
}
![](https://img-blog.csdnimg.cn/39c8fc0601d143198d8031830cb75ddf.png)
代码效果图:
![](https://img-blog.csdnimg.cn/3efc533f61de4aff920cf59dc6e2272b.png)
模拟面试题:
![](https://img-blog.csdnimg.cn/1e040f2de560452da4b37bf8a2cd7575.png)