当前位置: 首页 > news >正文

10.22 多进程间通信-共享内存、信号量集

练习:通过信号量集完成对共享内存的同步操作

案例代码:

分文件编译:信号量集部分

sem.h

#ifndef __SEM_H__
#define __SEM_H__
#include <myhead.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) */};//1创建信号量集并初始化
int get_sem_init(int semcount);//2.申请资源P操作
void P(int semid,int semnum);//3.释放资源V操作
void V(int semid,int semnum);//4.删除信号量集
void delete_sem(int semid);#endif

sem.c

#include "sem.h"
//初始化函数
void init_sem(int semid,int semnum){union semun buf;//准备共用体变量printf("请对第%d个信号量赋初始值:",semnum+1);scanf("%d",&buf.val);//给信号量初始化if(semctl(semid,semnum,SETVAL,buf)==-1){perror("semctl error");return ;}
}
//1创建信号量集并初始化
int get_sem_init(int semcount)
{//创建key值key_t key=ftok("/",'S');if(key==-1){perror("ftok error");return -1;}//使用key值创建信号量集int semid=semget(key,semcount,IPC_CREAT|IPC_EXCL|0664);if(semid==-1){if(errno==EEXIST){//表示信号量集已经存在,则不需要进行初始化,直接打开信号量集返回id号semid=semget(key,semcount,IPC_CREAT);return semid;}perror("semget error");return -1;}//初始化信号量集for(int i=0;i<semcount;i++){init_sem(semid,i);//调用初始化函数}//将信号量级ID返回return semid;
}//2.申请资源P操作
void P(int semid,int semnum){//定义进行操作的结构体struct sembuf buf;buf.sem_num=semnum;   //要操作的信号量的编号buf.sem_op=-1;   //表示申请1个资源buf.sem_flg=0;   //表示阻塞申请//执行操作函数if(semop(semid,&buf,1)==-1){perror("semop error");return ;}
}//3.释放资源V操作
void V(int semid,int semnum){//定义进行操作的结构体struct sembuf buf;buf.sem_num=semnum;  //要操作的信号量的编号buf.sem_op=1;  //表示释放1个资源buf.sem_flg=0;  //表示阻塞释放//执行操作函数if(semop(semid,&buf,1)==-1){perror("semop error");return ;}
}//4.删除信号量集
void delete_sem(int semid){//执行操作函数进行删除if(semctl(semid,0,IPC_RMID)==-1){perror("semctl error");return;}
}

 多进程间使用共享内存同步通信

shmsnd.c

#include <myhead.h>
#include "sem.h"
#define PAGE_SIZE 4096  //物理空间单位一页大小
int main(int argc, const char *argv[])
{//使用信号量级实现多个进程间同步操作int semid=get_sem_init(2);//信号量级个数为2//1.创建一个key值key_t key=ftok("/",'m');if(key==-1){perror("ftok error");return -1;}printf("key=%#x\n",key);//2.使用key值创建一个共享内存int shmid=shmget(key,PAGE_SIZE,IPC_CREAT|0664);if(shmid==-1){perror("shmget error");return -1;}printf("shmid=%d\n",shmid);//3.获取共享内存地址char *addr=(char *)shmat(shmid,NULL,0);if(addr==(void*)-1){perror("shmat error");return -1;}printf("addr=%p\n",addr);//4.往共享内存数据存放数据while(1){//申请0信号量资源进行P操作P(semid,0);fgets(addr,PAGE_SIZE,stdin);addr[strlen(addr)-1]='\0';//释放1信号量资源进行V操作V(semid,1);if(strcmp(addr,"quit")==0){break;}}//5.断开与共享内存的链接shmdt(addr);addr=NULL;return 0;
}

shmrcv.c

#include <myhead.h>
#include "sem.h"
#define PAGE_SIZE 4096  //物理空间单位一页大小
int main(int argc, const char *argv[])
{//使用信号量级实现多个进程间同步操作int semid=get_sem_init(2);//信号量集个数为2//1.创建一个key值key_t key=ftok("/",'m');if(key==-1){perror("ftok error");return -1;}printf("key=%#x\n",key);//2.使用key值创建一个共享内存int shmid=shmget(key,PAGE_SIZE,IPC_CREAT|0664);if(shmid==-1){perror("shmget error");return -1;}printf("shmid=%d\n",shmid);//3.获取共享内存地址char *addr=(char *)shmat(shmid,NULL,0);if(addr==(void*)-1){perror("shmat error");return -1;}printf("addr=%p\n",addr);//4.取出共享内存数据while(1){//申请1信号量资源进行P操作P(semid,1);sleep(3);printf("取出数据为:%s\n",addr);//释放0信号量资源进行V操作V(semid,0);if(strcmp(addr,"quit")==0){break;}}//5.断开与共享内存的链接shmdt(addr);addr=NULL;//6.删除共享内存if(shmctl(shmid,IPC_RMID,NULL)==-1){perror("shmctl error");return -1;}//删除信号量集delete_sem(semid);return 0;
}
结果:

 练习:使用封装好了的信号量集函数,完成实现三个进程,进程1输出‘A’,进程2输出'B',进程3输出‘C’。要求输出结果为ABCABCABCABCABC...

代码实现:
#include <myhead.h>
#include "sem.h"
void handler(int signo){if(signo==SIGCHLD){while(waitpid(-1,NULL,WNOHANG)>0);   //非阻塞回收僵尸进程}
}
int main(int argc, const char *argv[])
{//将子进程结束信号SIGCHLD与signal信号绑定函数进行绑定if(signal(SIGCHLD,handler)==SIG_ERR){perror("signal error");return -1;}//使用信号量级实现进程间同步int semid=get_sem_init(3);pid_t pid=fork();if(pid>0){//父进程pid_t pid1=fork();if(pid1>0){//父进程//申请0信号量资源进行P操作for(int i=0;i<5;i++){P(semid,0);putchar('A');sleep(1);fflush(stdout);//释放1信号量资源进行V操作V(semid,1);}}else if(pid1==0){//子进程//申请1信号量资源进行P操作for(int i=0;i<5;i++){P(semid,1);putchar('B');sleep(1);fflush(stdout);//释放2信号量资源进行V操作V(semid,2);}exit(EXIT_SUCCESS);//结束进程}else {perror("fork error");return -1;}}else if(pid==0){//子进程for(int i=0;i<5;i++){//申请2信号量资源进行P(semid,2);putchar('C');sleep(1);fflush(stdout);//释放0信号量资源进行V操作V(semid,0);}exit(EXIT_SUCCESS);  //结束进程}else {perror("fork error");return -1;}wait(NULL);//阻塞回收子进程资源,避免父进程提前结束wait(NULL);delete_sem(semid);//删除信号量集return 0;
}
结果: 

 思维导图

 

http://www.lryc.cn/news/466692.html

相关文章:

  • 输入输出管理器的使用
  • windows连接linux服务器上的jupyter lab
  • golang生成并分析cpu prof文件
  • 【Python爬虫实战】XPath与lxml实现高效XML/HTML数据解析
  • 软件测试学习笔记丨Selenium学习笔记:元素定位与操作
  • 在 HTML 中,<input> 元素支持的事件汇总
  • vue3【实战】 渲染 md 文件(markdown语法 .md后缀的文件)
  • Sora高端制造业WordPress外贸主题
  • windows安装superset及各种问题解决
  • JMeter模拟并发请求
  • 【小趴菜前端实习日记5】
  • 如何通过谷歌外推占据搜索引擎首页?
  • jmeter学习(6)逻辑控制器
  • Android14 和android12 在锁屏界面Keyguard输错5次密码后倒计时30秒时重启手机不显示倒计时
  • 智能时代摩托车一键启动无钥匙进入感受科技前线
  • 需要补充的技能
  • 15分钟学 Go 第 15 天:映射(Map)
  • element-plus 官方表格排序问题
  • AI语音模型在家宽业务中的应用
  • 零七生活API-文字转语音API使用示例
  • rpc的客户端为什么称为stub
  • RHCE--nginx实现多IP访问多网站
  • TikTok运营对IP有什么要求?
  • 大白话讲解:多模态大模型综述,通俗易懂!
  • 大数据-184 Elasticsearch - 原理剖析 - DocValues 机制原理 压缩与禁用
  • Java设计模式:工厂模式详解
  • 《Python游戏编程入门》注-第3章1
  • Java爬虫:获取数据的入门详解
  • GAMES104:17 游戏引擎的玩法系统:高级AI-学习笔记
  • 【Unity】Unity中获取网络时间进行每日和每月刷新