现在完成一个任务:
writer.c完成将键盘输入的内容写到共享内存,然后通知由reader.c创建的进程,其负责将从共享内存中读到的数据输出到屏幕上,然后通知writer.c创建的进程继续将从缓冲区读到的内容写到共享内存。当输入quit时,两个进程同时退出。同时还应该完成的是,可以有多个读者,当发出退出命令后,全部退出。
流程图:
writer.c
#include#include #include #include #include #include #include #include #include #define N 1024#define R 0#define W 1union semun //声明一个共用体,并定义一个共用体变量,该共用体的具体信息可以 man semctl{ int val; /* Value for SETVAL */}un;void p(int semid , int num); //声明对信号灯集semid的编号为num的信号进行P操作的函数void v(int semid, int num); //声明对信号灯集semid的编号为num的信号进行V操作的函数int main(){ key_t key; //声明一个密钥 int shmid, semid; //声明一个共享内存id和一个信号灯集id char *shmaddr = NULL; //用于存放共享内存的起始地址 if ((key = ftok(".", 'a')) == -1) //制造一个密钥 { perror("ftok"); exit(-1); } if ((semid = semget(key, 2, 0666 | IPC_CREAT | IPC_EXCL)) == -1) //不存在创建,存在报错 { if (errno == EEXIST)//last run { semid = semget(key, 2, 0666); //重新得到信号灯集的id } else { perror("semget"); exit(-1); } } else//first run //对于首先运行的进程完成对信号灯集的初始化 { //init R-0 un.val = 0; //将读资源初始化为0个 if (semctl(semid, R, SETVAL, un) == -1) { perror("init R"); exit(-1); } //init W-1 un.val = 1; //将写资源初始化为1个 if (semctl(semid, W, SETVAL, un) == -1) { perror("init R"); exit(-1); } } if ((shmid = shmget(key, N, 0666 | IPC_CREAT)) == -1) //得到共享内存的id { perror("shmget"); exit(-1); } if ((shmaddr = (char *)shmat(shmid, NULL, 0)) < (char *)0) //得到共享内存映射后的起始地址 { perror("shmat"); exit(-1); } while (1) { p(semid, W); //写之前先申请写资源 fgets(shmaddr, N, stdin); //将输入的内容写到共享内存 v(semid, R); //发送读信号 if (strncmp(shmaddr, "quit", 4) == 0) //看是否退出 break; } if (shmdt(shmaddr) == -1) //退出后,取消该进程对共享内存的映射,它的删除有另一方完成 { perror("shmdt"); exit(-1); } exit(0);}void p(int semid , int num) //定义P函数{ struct sembuf buf = {num, -1, 0}; if (semop(semid, &buf, 1) == -1) { perror("p w"); exit(-1); }}void v(int semid, int num) // 定义V函数{ struct sembuf buf = {num, 1, 0}; if (semop(semid, &buf, 1) == -1) { perror("v r"); exit(-1); }}
#include#include #include #include #include #include #include #include #include #define N 1024#define R 0#define W 1union semun //声明一个共用体,并定义一个共用体变量,该共用体的具体信息可以 man semctl{ int val; /* Value for SETVAL */}un;void p(int semid , int num); //声明对信号灯集semid的编号为num的信号进行P操作的函数void v(int semid, int num); //声明对信号灯集semid的编号为num的信号进行V操作的函数int main(){ key_t key; //声明一个密钥 int shmid, semid; //声明一个共享内存id和一个信号灯集id char *shmaddr = NULL; //用于存放共享内存的起始地址 struct shmid_ds buf; if ((key = ftok(".", 'a')) == -1) //制造一个密钥 { perror("ftok"); exit(-1); } if ((semid = semget(key, 2, 0666 | IPC_CREAT | IPC_EXCL)) == -1) { if (errno == EEXIST)//last run { semid = semget(key, 2, 0666); //重新得到信号灯集的id } else { perror("semget"); exit(-1); } } else//first run //对于首先运行的进程完成对信号灯集的初始化 { //init R-0 un.val = 0; //将读资源初始化为0个 if (semctl(semid, R, SETVAL, un) == -1) { perror("init R"); exit(-1); } //init W-1 un.val = 1; //将写资源初始化为1个 if (semctl(semid, W, SETVAL, un) == -1) { perror("init R"); exit(-1); } } if ((shmid = shmget(key, N, 0666 | IPC_CREAT)) == -1) //得到共享内存的id { perror("shmget"); exit(-1); } if ((shmaddr = (char *)shmat(shmid, NULL, 0)) < (char *)0) //得到共享内存映射后的起始地址 { perror("shmat"); exit(-1); } while (1) { p(semid, R); //读之前申请读资源 printf("%s", shmaddr); //将共享内存中内容输出到屏幕上 if (strncmp(shmaddr, "quit", 4) == 0) //看是否退出 { /* //退出之前先发一个读资源,完成唤醒另一个读者的作用,当写进程退出后,保证所有的读者全部退出, 而最后退出的读者删除共享内存和信号灯集 */ v(semid, R); break; } v(semid, W); //发送写信号 } if (shmdt(shmaddr) == -1) // 解除该进程的共享内存映射 { perror("shmdt"); exit(-1); } if (shmctl(shmid, IPC_STAT, &buf) == -1) //读取共享内存的信息 { perror("shmctl"); exit(-1); } if (buf.shm_nattch == 0) //判断该共享内存的映射数是否为0,说明这已经是最后一个读者了。如果是的话,删除共享内存和信号灯集 { if (shmctl(shmid, IPC_RMID, NULL) == -1) //删除共享内存 { perror("smmctl"); exit(-1); } if (semctl(semid, 0, IPC_RMID, NULL) == -1) //删除信号灯集 { perror("sem rm"); exit(-1); } } exit(0);}void p(int semid , int num) //定义P操作函数{ struct sembuf buf = {num, -1, 0}; if (semop(semid, &buf, 1) == -1) { perror("p r"); exit(-1); }}void v(int semid, int num) //定义V操作函数{ struct sembuf buf = {num, 1, 0}; if (semop(semid, &buf, 1) == -1) { perror("v w"); exit(-1); }}