博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
利用共享内存和信号灯集实现进程间同步一例
阅读量:6277 次
发布时间:2019-06-22

本文共 4190 字,大约阅读时间需要 13 分钟。

现在完成一个任务:

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); }}

reader.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; //用于存放共享内存的起始地址 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); }}

转载地址:http://pdyva.baihongyu.com/

你可能感兴趣的文章
android中用ExpandableListView实现三级扩展列表
查看>>
%Error opening tftp://255.255.255.255/cisconet.cfg
查看>>
java读取excel、txt 文件内容,传到、显示到另一个页面的文本框里面。
查看>>
《从零开始学Swift》学习笔记(Day 51)——扩展构造函数
查看>>
python多线程队列安全
查看>>
[汇编语言学习笔记][第四章第一个程序的编写]
查看>>
android 打开各种文件(setDataAndType)转:
查看>>
补交:最最原始的第一次作业(当时没有选上课,所以不知道)
查看>>
Vue实例初始化的选项配置对象详解
查看>>
PLM产品技术的发展趋势 来源:e-works 作者:清软英泰 党伟升 罗先海 耿坤瑛
查看>>
vue part3.3 小案例ajax (axios) 及页面异步显示
查看>>
浅谈MVC3自定义分页
查看>>
.net中ashx文件有什么用?功能有那些,一般用在什么情况下?
查看>>
select、poll、epoll之间的区别总结[整理]【转】
查看>>
CSS基础知识(上)
查看>>
PHP中常见的面试题2(附答案)
查看>>
26.Azure备份服务器(下)
查看>>
mybatis学习
查看>>
LCD的接口类型详解
查看>>
Spring Boot Unregistering JMX-exposed beans on shutdown
查看>>