进程间通信之共享内存及其shm函数的使用【Linux】

2024-01-07 16:44

本文主要是介绍进程间通信之共享内存及其shm函数的使用【Linux】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

进程间通信之共享内存及其shm函数的使用

  • 什么是共享内存
    • 共享内存的内核数据结构
  • 如何实现共享内存
    • 共享内存函数
      • shmget函数
        • ftok函数
      • shmat函数
      • shmdt函数
      • shmctl函数
  • 代码实现

什么是共享内存

  共享内存区是最快的IPC(Inter-Process Communication,进程间通信)形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据.
在这里插入图片描述
  匿名管道和命名管道都需要通过系统调用接口来实现进程间通信,因为管道属于文件,属于内核中的一种特殊数据结构,由OSweihu,所以只能使用系统调用。而共享内存存在堆栈之间,可以直接读写。双方进程若要进行通信,直接进行内存级的读写即可。

从下图可以更加直观的看到在内核照中的运行方式:

在这里插入图片描述

  • 共享内存的提供者是操作系统。
  • 共享内存缺乏访问控制,用户(进程)双方都不会影响对方,甚至不知道对方的存在,容易造成接受的数据是不完整的。
  • 共享内存 = 共享内存块 + 对应的共享内存的内核数据结构

共享内存的内核数据结构

在这里插入图片描述

如何实现共享内存

共享内存函数

shmget函数

功能:用来创建共享内存
原型: int shmget(key_t key, size_t size, int shmflg);
参数:
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

  参数key要保证在系统中的唯一性,key值相同,就是同一块共享内存,保证key的唯一性可以使用ftok函数实现:

ftok函数

所需要的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
函数原型:
key_t ftok(const char *pathname, int proj_id);
参数:
pathname:指定的文件,此文件必须存在且可存取
proj_id:计划代号(project ID),可以在[0, 255]中随机取一个数字。
函数返回值

  • 成功:返回key_t值(即IPC 键值)
  • 出错:-1,错误原因存于error中
    ftok函数把从pathname导出的信息与id的低序8位组合成一个整数IPC键(也就是shmget函数中需要的key值)。

  注意:如果在使用ftok的这段时间里,pathname指向的文件或者目录被删除而且又重新创建,ftok是能够成功返回的,但是由于inode可能不同了,返回值也就不同于所希望的值,由于key值相同,使用同一块共享内存,这时候就可能会导致key值不同,双方无法共享一块内存,所以这个pathname一定要是一个不会被修改的文件路径。


  对于shmget的第二个参数size,代表这个共享内存的大小,最好是页(PAGE:4096byte)的整数倍,(OS和磁盘进行I/O操作的基本单位也是4096byte),如果设置为4097byte,虽然只是多了一个字节,但是系统底层可能会创建4096 * 2的空间,即使这样,也只能使用自己申请的大小(4097byte),不能使用4096*2的空间。

第三个参数shmflg:

  • 该参数用于确定共享内存属性。
  • 使用上为:标志位 | 内存权限
  • 标志位参数有两种:IPC_CREAT、IPC_EXCL
  • 使用TPC_CREAT | 0666(内存权限):创建共享内存若底层存在,就获取,并返回,若不存在,就新建,并返回。
  • 使用TPC_CREAT | IPC_EXCL | 0666(内存权限):创建共享内存若底层存在,则出错返回。若不存在,则新建,并返回。所以返回的一定是一个全新的shm.

shmat函数

功能:将共享内存段连接到进程地址空间
原型: void *shmat(int shmid, const void *shmaddr, int shmflg);
参数:
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

使用这个函数建立物理内存和虚拟内存的映射。
shmaddr设置为nullptr表示让内核自己确定位置。
shmflg设置为0为默认方式。
使用shmat函数可以简单的这样:
char* shmaddr = (char*)shmat(shmid, nullptr, 0);

  • shmaddrNULL,核心自动选择一个地址
  • shmaddr不为NULLshmflgSHM_RND标记,则以shmaddr为连接地址。
  • shmaddr不为NULLshmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr -(shmaddr % SHMLBA)
  • shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

shmdt函数

功能:将共享内存段与当前进程脱离
原型:int shmdt(const void *shmaddr);
参数: shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段功能

shmctl函数

功能:用于控制共享内存
原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数:
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

 cmd的三个命令:

命令说明
IPC_STAT把shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_RMID删除共享内存段

shmctl常用IPC_RMID,用于删除共享内存空间。

代码实现

//server.cpp
// 由server再共享内存里面读取信息#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#include <string.h>
#include <unistd.h>
#include <string>
#include <cstdlib>
const int SIZE = 4094;
int main()
{key_t key = ftok(".", 113);if (key < 0){perror("ftok");exit(1);}int shmid = shmget(key, SIZE, IPC_CREAT | 0666);if (shmid < 0){perror("shmget");exit(2);}char *addr = (char *)shmat(shmid, NULL, 0);int i = 0;while (i < 20){i++;printf("client# %s\n", addr);fflush(stdout);memset(addr, 0, sizeof(addr)); // 每次写入都清空,保证共享内存中没有上一次的数据残留。sleep(1);}shmdt(addr);shmctl(shmid, IPC_RMID, NULL);return 0;
}
// client.cpp
// 由client再共享内存里面发送信息#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <error.h>
#include <string.h>
#include <unistd.h>
#include <cstdlib>
const int SIZE = 4094;
int main()
{key_t key = ftok(".", 113);if (key < 0){perror("ftok");exit(1);}int shmid = shmget(key, SIZE, IPC_CREAT | 0666);if (shmid < 0){perror("shmget");exit(2);}char *addr = (char *)shmat(shmid, NULL, 0);int i = 0;while (i < 15){fgets(addr, 100, stdin);fflush(stdin);sleep(1);i++;}shmdt(addr);return 0;
}
// makeflie
.PHONY:all
all:server clientserver:server.cppg++ -o $@ $^client:client.cppg++ -o $@ $^.PHONY:clean
clean:rm -f server client

  上面的代码是实现一个由客户端进行在终端上进行写入信息到共享内存,服务端从共享内存读出到终端打印到屏幕上的一个过程。


    😄 创作不易,你的点赞和关注都是对我莫大的鼓励,再次感谢您的观看😄

  • List item

这篇关于进程间通信之共享内存及其shm函数的使用【Linux】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/580589

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal