Linux进程间通信学习记录(IPC 机制、共享内存以及信号灯集)

0.System V IPC机制:

        ①.IPC对象包含:共享内存、消息队列和信号灯集。

        ②.每个IPC对象有唯一的ID。

        ③.IPC对象创建后一直存在,直到被显示地删除。

        ④.每一个IPC对象有一个关联的KEY。(其他进程通过KEY访问对应的IPC对象)

        ⑤.ipcs(显示系统所有的IPC对象)、ipcrm

一. 生成KEY值 - ftok

功能

        成功时返回(合法的key值),失败时返回(EOF)。

        若传入的参数一样,那么得到的key值也一样

参数

        path:存在且可访问的文件的路径

        proj_id:用于生成key的数字,不能为0,一般为字符常量

int key_t ftok(const char *path,int proj_id);
int main(int argc,char *argv[])
{key_t key;key = ftok(".",'a');if(-1 == key){perror("key error");exit(-1);}
}

二.共享内存

0.特点

        ①.共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。

        ②.共享内存在内核空间创建,可被进程映射到用户空间访问,使其灵活。

        ③.由于多个进程可同时访问共享内存,因此需要同步和互斥机制配合使用

        ④.共享内存的大小有限制

1.创建/打开共享内存 - shmget()

功能

        创建/打开共享内存对象

        成功时返回(共享内存的id),失败时(EOF)

参数

        key:和共享内存关联的key,IPC_PRIVATE或由ftok生成。

        size:共享内存的大小,单位为字节。

        shmflg:共享内存标志位 IPC_CREATE | 0666(不存在就创建,存在了就打开)。

int shmget(key_t key,int size,int shmflg);

示例1:创建一个私有的共享内存,大小为512字节,权限为0666

int shmid;shmid = shmget(IPC_PRIVATE,512,0666);
if(0 > shmid)
{perror("shmget error");exit(-1);
}

示例2:创建/打开一个和key关联的共享内存,大小为1024字节,权限为0666

key_t key;
int shmid;/* 1.先生成key(相关的进程调用ftok时,传入相同的参数才能得到相同的key) */
key = ftok(".",'m');
if(-1 == key)
{perror("ftok");exit(-1);
}/* 2.获取共享内存 */
shmid = shmget(key,1024,IPC_CREATE | 0666);
if(0 > shmid)
{perror("shmget");exit(-1);
}

2.映射共享内存 - shmat

功能

        映射共享内存;

        成功时返回(映射后的地址),失败时返回((void *)-1),通过指针访问共享内存,指针类型取决于共享内存中存放的数据的类型;

参数

        shmid:要映射的共享内存的id。

        shmaddr:指定映射后的地址(通常传入NULL),NULL表示由系统自动映射。

        shmflg:标志位,0表示可读写;SHM_RDONLY表示只读。

void *shmat(int shmid,const void *shmaddr,int shmflg);

示例1:在共享内存中存放键盘输入的字符串

char *addr;    //保存映射后的首地址
int shmid;/* 映射共享内存 */
addr = (char *)shmat(shmid,NULL,0);
id((char *)-1 == addr)
{perror("shmat");exit(-1);
}
fgets(addr,N,stdin);

3.读写共享内存

        操作映射的共享内存的地址

4.撤销共享内存映射 - shmdt

功能

        撤销共享内存映射

        成功时返回(0),失败时返回(EOF)

参数

        shmaddr:映射共享内存的首地址

int shmdt(void *shmaddr);

5.共享内存控制 - shmctl

功能

        控制共享内存。

        成功时返回(0),失败时返回(-1)并设置errno。

参数

        shmid:要操作的共享内存的id。

        cmd   :要执行的操作

                        IPC_STAT:获取当前共享内存的属性(大小,关联的key值,权限等),存入到                                                shmid_ds *buf中

                        IPC_SET  :将属性(先在shmid_ds *buf中填充)设置到共享内存的id中

                        IPC_RMID:删除一个共享内存的id

        buf:保存或设置共享内存属性的地址

int shmctl(int shmid,int cmd,struct shmid_ds *buf);

6.删除共享内存对象 - shmctl

 用shmctl来删除共享内存对象(应该由最后一个进程来执行此操作)

 功能

        添加删除标记,当每一个进程都撤销共享内存映射后(nattach == 0)才真正的删除。        

shmctl(shmid,IPC_RMID,NULL);

三.信号灯

1.含义:

        信号灯也叫信号量,用于进程/线程同步或互斥的机制;

        System V 信号灯是一个或多个计数信号灯的集合;

        System V 信号灯可同时操作集合中的多个信号灯,要么都能申请到资源,要么都申请不到资          源;

        System V 信号灯申请多个资源时避免死锁;

 2.信号灯的类型:

         Posix无名信号灯:通常用于线程同步

         Posix有名信号灯:通常用于进程间的同步和互斥

         System V 信号灯:通常用于进程间的同步和互斥

四.System V 信号灯使用步骤

1.打开/创建信号灯 - semget

功能

        打开/创建信号灯

        成功时返回(信号灯集合的id),失败时返回(-1),返回(-1)有可能是 打开/创建 失败。所以在返回(-1)时 要对 errno 进行判断,若 errno = EEXIST ,则是该信号灯已经存在,此时进行打开操作;否则应该退出程序,并打开错误信息。

参数

        key:和信号灯关联的key值(IPC_PRIVATE 或 ftok生成的);

        nsems:集合中包含的计数信号灯的个数;

        semflg:标志位

                        IPC_CREAT | 0666:没有则创建;

                        IPC_EXCL:检查信号灯集合是不是第一次被创建,若不是第一次被创建则会返回                                             (EEXIST),保证信号灯只被初始化一次;

int semget(key_t key,int nsems,int semflg);
semid = semget(sem_key,1,IPC_CREATE|IPC_EXCL|0666);
/* 若打开/创建失败 */
if(-1 == semid) 
{/* errno == EEXIST 时表示该信号灯已经存在,只能进行打开操作 */if(errno == EEXIST){semid = semget(sem_key,1,0777);}/* 否则为出错,应该退出程序 */else{perror("fail to semget");exit(-1);}
}
/* 若创建成功,则初始化信号灯 */
else
{/* 初始化操作 */
}

2.信号灯初始化 - semctl

功能

        初始化信号灯集合;

        成功时返回(0),失败时返回(EOF);

参数

        semid:要操作的信号灯集合id

        semnum:要操作的集合中的信号灯编号(信号灯集合中的哪一个信号灯)

        cmd:要执行的操作

                        SETVAL:设置信号灯的值

                        IPC_RMID:删除信号灯集合

        union semun  :要设置的信号灯的值

int semctl(int semid,int semnum,int cmd,...);
union semun myun;/* 1.填充第一个要初始化的信号的值 */
myun.val = 2;
/* 把第一个信号灯的值初始化为2 */
if(0 > semctl(semid,0,SETVAL,myun))
{perror("semctl");exit(-1);
}/* 1.填充第二个要初始化的信号的值 */
myun.val = 0;
/* 把第二个信号灯的值初始化为0 */
if(0 > semctl(semid,1,SETVAL,myun))
{perror("semctl");exit(-1);
}

3.P/V 操作 - semop

功能

        对信号灯集合中的一个或多个信号灯执行操作;

        成功时返回(0),失败时返回(-1);

参数

        semid:要操作的信号灯集id;

        sops:描述对某一个信号灯操作的结构体。若要操作多个信号灯,则要传入结构体数组;

        nsops:要操作的信号灯的个数;

int semop(int semid,struct sembuf *sops,unsigned nsops);
struct sembuf
{short semnum;    //指定要操作的信号灯的编号/* 指定要执行的操作(-1:P操作,1:V操作) */short sem_op;    /* 一般为 0/IPC_NOWAIT/SEM_UNDO (0         :表示以阻塞的方式,直到完成操作IPC_NOWAIT : 表示不阻塞,直接返回) SEM_UNDO : 进程退出后,将信号量返回到其初始值(防止死锁)   */short sem_flg;    
};
    struct sembuf buf[3];/* 填充第 0 个信号 */buf[0].sem_num = 0;     //操作第 0 个信号灯buf[0].sem_op = -1;     //指定执行 P 操作buf.sem_flg = 0;        //以阻塞的方式完成操作/* 填充第 1 个信号 */buf[1].sem_num = 1;     //操作第 1 个信号灯buf[1].sem_op = -1;     //指定执行 P 操作buf[1].sem_flg = 0;     //以阻塞的方式完成操作/* 调用 semop 完成P/V操作,操作的信号灯的个数为 2  */semop(semid,buf,2);

3.删除信号灯 - semctl

功能

        删除信号灯集合;

        成功时返回(0),失败时返回(EOF);

参数

        semid:要操作的信号灯集合id

        semnum:要操作的集合中的信号灯编号(信号灯集合中的哪一个信号灯)

        cmd:要执行的操作

                        SETVAL:设置信号灯的值

                        IPC_RMID:删除信号灯集合

int semctl(int semid,int semnum,int cmd,...);
semctl(semid,0,IPC_RMID);

五.用信号灯集实现共享内存同步

1.目的:

        父子进程通过System V 信号灯同步对共享内存的读写,需要创建两个信号灯,一个用于写资源,一个用于读资源

        父进程从键盘输入字符串到共享内存

        子进程删除字符串中的空格并打印

        父进程输入 quit 后,删除共享内存和信号灯集,程序结束

2.流程图

3.代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>void init_sem(int semid , int s[] , int n);
void pv(int semid,int num,int op);#define N   64      //共享内存的大小
#define READ    0   //信号灯集合中的信号灯的编号,代表可读缓冲区
#define WRITE   1   //信号灯集合中的信号灯的编号,代表可写缓冲区/* 用于信号灯集合操作, man 手册里有这个共用体,但是得自己定义 */
union semun
{int val;struct semid_ds *buf;unsigned short *array;struct seminfo *__buf;
};int main(void)
{/*** 0.定义所要用到的变量* (1)共享内存的id* (2)信号灯集合id* (3)信号灯初始化数组* (4)pid* (5)key* (6)共享内存映射后的首地址*/int shmid;          //共享内存的idint semid;          //信号灯集合idint s[] = {0,1};    //信号灯初始化数组,s[0]用于读,s[1]用于写pid_t pid;          //用于创建进程key_t key;          //用于生成keychar *shmaddr;      //用于接收映射的共享内存的首地址/* 1.创建/获取key */key = ftok(".",'s');if(-1 == key){perror("ftok error");exit(-1);}/* 2.创建/获取共享内存 */shmid = shmget(key,N,IPC_CREAT | 0666);if(0 > shmid){perror("shmget error");exit(-1);}/* 3.创建信号灯集合(若失败则在退出程序前,要先把创建号的共享内存删除) */semid = semget(key,2,IPC_CREAT | 0666);if(0 > semid){perror("semget error");goto _error1;       //处理错误}/* 4.对信号灯集合进行初始化,初始化 2 个信号量 */init_sem(semid,s,2);/* 5.映射共享内存(64)个字节,(若映射共享内存失败,在退出程序前,要先把之前创建的信号灯集合删除) */shmaddr = (char *)shmat(shmid,NULL,0);if(((void *)-1) == shmaddr){perror("shmat error");goto _error2;}/* 6.创建子进程 */pid = fork();switch(pid){case -1:perror("fork error");goto _error2;break;/* 子进程 */case 0:{char *p,*q;while(1){/* 1.对可读资源进行 P 操作 */pv(semid,READ,-1);/* 2.进行读操作(去除共享内存中的空格) */p = q = shmaddr;while(*q){if(*q != ' '){*p++ = *q;}q++;}*p = '\0';printf("result:%s\n",shmaddr);/* 3.对可写资源执行 V 操作,使其他进程可写 */pv(semid,WRITE,1);}break;}/* 此进程 */default:while(1){/* 7.要写缓冲区,所以先进行P操作,看有没有资源可写。若没有资源可写,则阻塞等待 */pv(semid,WRITE,-1);/* 8.执行写操作 */printf("input >\n");fgets(shmaddr,N,stdin);/* 9.若输入了quit,则跳出循环 */if(0 == strcmp(shmaddr,"quit\n"))break;/* 10.执行完写操作后,执行 V 操作,使其他进程可读 */pv(semid,READ,1);}/* 发出信号,结束子进程 */kill(pid,SIGUSR1);break;}/* 若创建信号灯集合失败,则在退出程序前,要先把创建号的共享内存删除 */
_error1:shmctl(shmid,IPC_RMID,NULL);/* 若映射共享内存失败,在退出程序前,要先把之前创建的信号灯集合删除 */
_error2:semctl(semid,0,IPC_RMID);return 0;
}/*** @description:    初始化信号灯集合* @param - semid:  信号灯集合的id* @param - s[]  :  信号灯初始化值的数组* @param - n    :  初始化信号灯的个数  * @return       :  无 
*/
void init_sem(int semid , int s[] , int n)
{int i;union semun myun;       //创建信号灯集合共用体/* 循环完成信号灯集合的初始化 */for(i = 0;i < n;i++){myun.val = s[i];semctl(semid,i,SETVAL,myun);}}/*** @description:        对信号灯集合的某一个信号灯实现P/V操作* @param - semid   :   信号灯集合id* @param - num     :   信号灯集合内的信号灯的编号* @param - op      :   实现的操作* @return          :   无
*/
void pv(int semid,int num,int op)
{struct sembuf buf;buf.sem_num = num;      //指定操作编号为 num 的信号灯buf.sem_op = op;        //指定要执行的操作buf.sem_flg = 0;        //阻塞等待,直到该操作完成/* 进行P/V操作 */semop(semid,&buf,1);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/404204.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu安装Anaconda3

本文详细阐述了在 Ubuntu 系统中安装 Anaconda3 的完整流程。包括 Anaconda3 安装包的获取途径&#xff0c;具体安装过程中的每一个步骤及注意事项&#xff0c;还有安装后的环境变量设置和安装成功的验证方法。旨在为 Ubuntu 用户提供清晰、易懂且准确的 Anaconda3 安装指南&am…

Unity--AssetBundle AB包管理器

1.简介 AB包&#xff08;AssetBundle&#xff09;是Unity中用于资源管理的一种机制&#xff0c;它允许开发者将多个文件&#xff08;如纹理、模型、音频等&#xff09;打包成一个单独的文件&#xff0c;以便于在游戏运行时动态加载和卸载。 但是现在出现了最新的Addressable来…

docker部署drawio

1&#xff09;介绍Drawio.io GitHub&#xff1a;GitHub - jgraph/drawio: draw.io is a JavaScript, client-side editor for general diagramming. Draw.io是一款开源的绘制流程图的工具&#xff0c;拥有大量免费素材和模板。程序本身支持中文在内的多国语言&#xff0c;创建…

【学习笔记】多元线性回归模型 —— Matlab

文章目录 前言一、多元线性回归多元线性回归模型线性模型 ( Y , X β , σ 2 I n ) (Y,X\beta,\sigma^2I_n) (Y,Xβ,σ2In​) 考虑的主要问题多元线性回归模型的参数估计多元线性回归模型和回归系数的检验 二、示例三、代码实现----Matlab1.多元回归的实现2.逐步回归的实现3.M…

图像增强技术简介

目录 一、概论 二、图像噪声 三、图像增强处理分类 一、概论 图像增强作为基本的图像处理技术&#xff0c;其目的是对图像进行加工&#xff0c;以得到对具体应用来说视觉效果更“好”更“有用”的图像。图像增强算法并不能增加原始图像的信息&#xff0c;而是通过某种技术手…

MVCC 详解

MVCC 简单理解 MVCC&#xff0c;全称 Multi-Version Concurrency Control&#xff0c;是多版本并发控制的意思。 在高并发情况下操作数据库可能会出现脏写、脏读、不可重复度、幻读这四个问题。通过 MVCC 可以实现在不加锁的前提下避免一些问题。 MVCC 的实现原理 多版本 …

相似度计算方法-编辑距离 (Edit Distance)

定义 编辑距离&#xff08;Edit Distance&#xff09;&#xff0c;也称为Levenshtein距离&#xff0c;是一种衡量两个字符串相似度的方法。它定义为从一个字符串转换为另一个字符串所需的最少单字符编辑操作次数&#xff0c;这些操作包括插入、删除或替换一个字符。 计算方法 …

Openstack二层网络的构建和使用

Openstack二层网络的构建和使用 一、实验目的 &#xff08;1&#xff09;了解网络层级、子网、动态地址、网关代理等概念并进行应用。 &#xff08;2&#xff09;了解OpenStack项目以及相关组件。 &#xff08;3&#xff09;了解 Neutron 二层网络的构建和使用。 二、实验原…

tomcat Listener 内存马浅谈

本文来源无问社区&#xff0c;更多实战内容可前往查看http://www.wwlib.cn/index.php/artread/artid/3651.html Tomcat 介绍 Tomcat的主要功能 toncat作为一个web服务器&#xff0c;实现了两个核心的功能 http 服务器功能&#xff1a;进行socket 通信&#xff08;基于TCP/I…

案例分享—国外深色UI界面设计赏析

在国外&#xff0c;深色界面设计&#xff08;Dark Mode&#xff09;已成为提升用户体验的重要趋势。它不仅有效减少屏幕亮度&#xff0c;保护用户视力&#xff0c;还能在夜晚或低光环境下提供更加舒适的浏览体验。设计师们普遍认识到&#xff0c;深色主题不仅提升了应用的视觉层…

Vue中下载内容为word文档

1.使用 html-docx-js&#xff1a;这是一个将 HTML 转换为 Word 文档的库。 2. 利用 Blob 和 FileSaver.js&#xff1a;创建并下载生成的 Word 文档。 在 Vue.js 中实现步骤如下: 1. npm 安装 html-docx-js 和 file-saver npm install html-docx-js npm install file-saver2.…

【vue教程】六. Vue 的状态管理

目录 往期列表本章涵盖知识点回顾Vuex 的基本概念什么是 Vuex&#xff1f;为什么需要 Vuex&#xff1f; Vuex 的核心概念stategettersmutationsactionsmodules Vuex 的安装和基本使用安装 Vuex创建 store在 Vue 应用中使用 store在组件中访问和修改状态 Vuex 的模块化模块化的好…

2024新型数字政府综合解决方案(七)

新型数字政府综合解决方案通过集成人工智能、大数据、区块链和云计算技术&#xff0c;创建了一个高度智能化和互联互通的政府服务平台&#xff0c;旨在全面提升行政效率、服务质量和透明度。该平台实现了跨部门的数据整合与实时共享&#xff0c;利用人工智能进行智能决策支持和…

PCRNet: Point Cloud Registration Network using PointNet Encoding 论文解读

目录 一、导言 二、先导知识 1、Frobenius范数 三、相关工作 1、点云配准工作 2、PointNet 3、基于深度学习的点云配准 四、PCRNet 1、PCRNet 2、Iterative PCRNet 3、损失函数 五、实验 一、导言 本论文收录于CVPR2019&#xff0c;本论文提出了一种依赖PointNet网…

11.2.0.4 RAC 节点1重做操作系统后如何复原

环境描述&#xff1a;Redhat7.9 11.2.0.4 RAC 双节点 实验背景 群里有大佬在交流RAC中1个节点操作系统坏了如何修复&#xff0c;故有了该实验。 在正常的生产环境当中&#xff0c;有时候会遇到主机磁盘以及其他硬件故障导致主机OS系统无法启动&#xff0c;或者OS系统本身故障…

【海奇HC-RTOS平台E100-问题点】

海奇HC-RTOS平台E100-问题点 ■ btn 没有添加到group中 &#xff0c;怎么实现的事件的■ 屏幕是1280*720, UI是1024*600,是否修改UI■ hc15xx-db-e100-v10-hcdemo.dtb 找不到■ 触摸屏驱动 能否给个实例■ 按键驱动■ __initcall(projector_auto_start)■ source insigt4.0 #if…

【esp32程序编译提示undefined reference to ‘xxxx‘】

案例1&#xff1a; 【背景】 在使用SquareLine Studio设计UI时&#xff0c;成功导出UI代码&#xff0c;在编译代码的时候提示undefined reference to ‘ui_img_1869164015’&#xff0c;有一个变量无法识别&#xff0c;没有定义。 【定位步骤】 1.首先找到用这个变量的.c文件…

复现DOM型XSS攻击(1-8关)

目录 第一关&#xff1a;​ 分析代码&#xff1a; 第二关&#xff1a; 分析代码&#xff1a; 第三关&#xff1a; 分析代码&#xff1a; 第四关&#xff1a; 分析代码&#xff1a; 第五关&#xff1a; 分析代码&#xff1a; 第六关&#xff1a; 分析代码&#xff1…

SpringBoot依赖之Spring Data Redis 一 List 类型

概念 Spring Data Redis (AccessDriver) 依赖名称: Spring Data Redis (AccessDriver)功能描述: Advanced and thread-safe Java Redis client for synchronous, asynchronous, and reactive usage. Supports Cluster, Sentinel, Pipelining, Auto-Reconnect, Codecs and muc…

Spring源码-源码层面讲解bean标签添加了lookup-method和replaced-method标签之后源码执行流程,以及对象实例化的流程

bean.xml文件添加lookup-method和replaced-method标签 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sch…