学习IO的第八天
作业:使用信号灯循环输出ABC
sem.c
#include <head.h>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) */
};//初始化函数
int init_sem(int semid, int semno)
{int val = -1;printf("请输入编号为%d的灯的初始值:", semno);scanf("%d", &val);getchar(); //吸收scanf留下的回车//对当前灯进行赋初始值//定义一个共用体变量union semun us;us.val = val; //要赋的值if(semctl(semid, semno, SETVAL, us) == -1){perror("semctl error\n");return -1;}//成功返回0return 0;
}//信号灯集的申请,初始化信号灯,并返回信号灯集的id
int create_sem(int semcount)
{//1.创建key值key_t key = ftok("/", 'y');if(key == -1){perror("ftok error\n");return -1;}//2.通过key值创建一个信号灯集int semid = semget(key, semcount, IPC_CREAT|IPC_EXCL|0664);if(semid == -1){if(errno == EEXIST){//信号灯集已经存在,无需创建直接打开即可semid = semget(key, semcount, IPC_CREAT);return semid; //之后的进程打开信号灯集只需返回id即可,无需进行初始化操作}perror("semget error\n");return -1;}//3.给信号灯集中的信号灯进行初始化操作for(int i=0;i<semcount;i++){init_sem(semid, i); //初始化编号为i的灯value值}//4.返回信号灯集的idreturn semid;
}//申请信号灯资源操作P操作
int P(int semid, int semno)
{//定一个操作的结构体变量struct sembuf buf;buf.sem_num = semno; //要操作的灯的编号buf.sem_op = -1; //表示申请资源操作buf.sem_flg = 0; //如果没有资源,则阻塞等待//调用semop函数完成P操作if(semop(semid, &buf, 1) == -1){perror("semop error\n");return -1;}return 0; //成功返回0
}//释放信号灯资源操作 v操作
int V(int semid, int semno)
{//定一个操作的结构体变量struct sembuf buf;buf.sem_num = semno; //要操作的灯的编号buf.sem_op = 1; //表示释放资源操作buf.sem_flg = 0; //如果没有资源,则阻塞等待//调用semop函数完成V操作if(semop(semid, &buf, 1) == -1){perror("semop error\n");return -1;}return 0; //成功返回0}//信号灯集的删除
int del_sem(int semid)
{if(semctl(semid, 0, IPC_RMID, 0) == -1){perror("del error\n");return -1;}return 0;
}
主函数
#include <head.h>
#include "sem.h"#define PAGE_SIZE 4096int main(int argc, const char *argv[])
{//创建一个信号灯集int semid = create_sem(3); //创建一个信号灯集包含两个灯,并初始化if(semid == -1){perror("create_sem error\n");return -1;}//创建的key值key_t key = ftok("/", 'y');if(key == -1){perror("ftok error\n");return -1;}printf("key = %#x\n", key);//通过key值创建共享内存段int shmid = shmget(key, PAGE_SIZE, IPC_CREAT|0664);if(shmid == -1){perror("shmget error\n");return -1;}printf("shmid = %d\n", shmid);//将共享内存段映射到用户空间char *addr = (char *)shmat(shmid, NULL, 0);if(addr == (void *)-1){perror("shmat error\n");return -1;}printf("addr = %p\n", addr); //输出映射的虚拟地址pid_t pid = -1;pid = fork();if(pid > 0){pid_t pid2 = fork();if(pid2 > 0){//父进程int count =0;while(1){//V操作,释放1灯的资源 P(semid,0);printf("A");count++;fflush(stdout); //每个进程的用户空间相互独立,缓冲区不同V(semid,1);if(count == 5){break;}} wait(NULL);wait(NULL);wait(NULL);}else if(pid2 == 0){//子进程2int count=0;while(1){//P操作,等待0灯的资源P(semid, 2);printf("C\n");count++;V(semid, 0);if(count == 5){break;}}exit(EXIT_SUCCESS);}else{perror("fork2 error\n");return -1;}}else if(pid == 0){//子进程1int count=0;while(1){//P操作,等待1号灯的资源P(semid, 1);printf("B");count++;fflush(stdout);//V操作,释放0号灯的资源V(semid,2);if(count == 5){break;}}exit(EXIT_SUCCESS);}else {perror("fork1 error\n");return -1;}if(shmdt(addr) == -1){perror("shmdt error\n");return -1;}del_sem(semid);return 0;
}
现象