【Linux初阶】system V - 共享内存

文章目录

  • 前言
  • 一、共享内存初识
    • 1.共享内存的原理
    • 2.理解共享内存
    • 3.共享的内存的概念
  • 二、共享内存函数
    • 1.shmget函数
    • 2.shmat函数
    • 3.shmdt函数
    • 4.shmctl函数
  • 三、共享内存的查看方法及其特征
  • 四、共享内存的代码实现
  • 五、共享内存优缺点分析
    • 1.共享内存的优点
    • 2.共享内存的缺点
  • 六、共享内存内核数据结构理解
  • 结语


前言

共享内存区是最快的IPC(进程间通信)形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。


一、共享内存初识

1.共享内存的原理

在物理内存中申请一块空间,将创建好的内存映射进进程的地址空间中,然后将地址空间这块区域的起始地址返回给上层用户,用户最终可以通过访问起始地址的方式实现对内存的访问。

照猫画虎,同样的一块内存空间可以映射进另一个进程的地址空间中,返回起始地址给用户,另一个进程的上层用户也可以实现的同一块内存的访问,最终实现进程间通信。

未来不想通信:a.取消进程和内存的映射关系; b.释放内存。

在这里插入图片描述

这一块被进程共享的内存称为 共享内存。将创建好的进程映射进进程的地址空间,我们称这个步骤为进程和共享内存挂接。而取消进程与共享内存的映射我们称之为 去关联

———— 我是一条知识分割线 ————

2.理解共享内存

  1. system V - 共享内存版本的进程间通信,是专门设计的,用于IPC(进程间通信)。
  2. 共享内存是一种通信方式,所有想通信的进程,都可以使用。
  3. OS中一定会同时存在很多的共享内存。

3.共享的内存的概念

通过让不同进程,看到同一个内存块的方式,我们就称之为:共享内存


二、共享内存函数

常识补充:shm - 共享内存

1.shmget函数

功能:用来创建共享内存
原型
 int shmget(key_t key, size_t size, int shmflg);
参数
 key:这个共享内存段名字
 size:共享内存大小
 shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1
  • key能进行共享内存的唯一性标识,它是由 ftok() 函数得来的。
  • shmflg常见参数有两个:IPC_CREAT、IPC_EXCL。
  • IPC_CREAT- 如果不存在,创建之,如果存在,获取之。
  • IPC_EXC - 无法单独使用,使用方法: IPC_CREAT | IPC_EXC, 如果不存在,创建之,如果存在,就返回出错(说明:如果创建成功,一定是新的ssh)

共享内存 = 物理内存块 + 共享内存的相关属性,我们在申请共享内存的时候,也要对共享内存做管理,管理方法:将共享内存的属性对象用数据结构(struct shmid_ds)的方式管理起来

注意:key的信息会被 shmget函数设置进共享内存的属性对象中保存起来

2.shmat函数

功能:将共享内存段连接到进程地址空间
原型
 void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
 shmid: 共享内存标识
 shmaddr:指定连接的地址
 shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1
  • 说明
shmaddr为NULL,核心自动选择一个地址
shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - 
(shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

3.shmdt函数

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

4.shmctl函数

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

在这里插入图片描述


三、共享内存的查看方法及其特征

  • 共享内存的命令行式查看方法
ipcs -m		#查看被用户使用的共享内存
ipcrm -m shmip	  #删除特定shmip的共享内存

共享内存的特征:共享内存的生命周期是跟随OS的,不是跟随进程的。也就是说,我们需要在指令行下对自己创建的用户级共享内存进行手动删除


四、共享内存的代码实现

  • 测试代码结构
# ls
client.c comm.c comm.h Makefile server.c

# cat Makefile 
.PHONY:all
all:server client
client:client.c comm.c
	gcc -o $@ $^
server:server.c comm.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f client server
  • comm.h
#ifndef COMM_H //把头文件的内容都放在#ifndef和#endif中,可避免头文件被多个文件引用产生的冲突
#define COMM_H

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define PATHNAME "."
#define PROJ_ID 0x6666

int createShm(int size);
int destroyShm(int shmid);
int getShm(int size);

#endif
  • comm.c
#include "comm.h"

static int commShm(int size, int flags)
{
	key_t _key = ftok(PATHNAME, PROJ_ID);
	if (_key < 0) {
		perror("ftok");
		return -1;
	}
	int shmid = 0;
	if ((shmid = shmget(_key, size, flags)) < 0) {
		perror("shmget");
		return -2;
	}
	return shmid;
}

int destroyShm(int shmid)
{
	if (shmctl(shmid, IPC_RMID, NULL) < 0) {
		perror("shmctl");
		return -1;
	}
	return 0;
}

int createShm(int size)
{
	return commShm(size, IPC_CREAT | IPC_EXCL | 0666);
}

int getShm(int size)
{
	return commShm(size, IPC_CREAT);
}
  • server.c
#include "comm.h"

int main()
{
	int shmid = createShm(4096);

	char* addr = shmat(shmid, NULL, 0);
	sleep(2);
	int i = 0;
	while (i++ < 26) {
		printf("client# %s\n", addr);
		sleep(1);
	}

	shmdt(addr);
	sleep(2);
	destroyShm(shmid);
	return 0;
}
  • client.c
#include "comm.h"

int main()
{
	int shmid = getShm(4096);
	sleep(1);
	char* addr = shmat(shmid, NULL, 0);
	sleep(2);
	int i = 0;
	while (i < 26) {
		addr[i] = 'A' + i;
		i++;
		addr[i] = 0;
		sleep(1);
	}

	shmdt(addr);
	sleep(2);
	return 0;
}
  • 运行结果

在这里插入图片描述

  • ctrl+c终止进程,再次重启
# ./server 
shmget: File exists

# ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status 
0x66026a25 688145 root 666 4096 0 
 
# ipcrm -m 688145 #删除shm ipc资源,注意,不是必须通过手动来删除,这里只为演示相关指令,删除IPC资源是进
程该做的事情

五、共享内存优缺点分析

1.共享内存的优点

优点:在所有进程间通信的方法中,共享内存的速度是最快的

如果使用管道,用户拷贝 6次,键盘的输入数据 -> 语言级缓冲区 -> 进程对应的文件缓冲区 -> 管道 -> 另一个进程对应的文件缓冲区 -> 语言级缓冲区 -> 屏幕。

如果使用共享内存,用户拷贝 4次,键盘的输入数据 -> 语言级缓冲区 -> 共享内存 -> 语言级缓冲区 -> 屏幕。

我们知道,在企业的数据通信中,数据往往非常庞大,此时使用共享内存可以大大降低拷贝次数

2.共享内存的缺点

缺点:共享内存不会给我们进行同步和互斥操作,没有对我们的数据做任何保护

也就是说,共享内存没有对写端在写、读端不读,写端不写、读端一直读,共享内存数据已满等情况,做相应的阻塞或其他保护。

通常情况下,工程师们会对共享内存进行一定的封装,实现对共享内存的保护。


六、共享内存内核数据结构理解

下面是共享内存暴露给用户的用户级数据结构:

struct shmid_ds {
 struct ipc_perm shm_perm; /* operation perms */
 int shm_segsz; /* size of segment (bytes) */
 __kernel_time_t shm_atime; /* last attach time */
 __kernel_time_t shm_dtime; /* last detach time */
 __kernel_time_t shm_ctime; /* last change time */
 __kernel_ipc_pid_t shm_cpid; /* pid of creator */
 __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
 unsigned short shm_nattch; /* no. of current attaches */
 unsigned short shm_unused; /* compatibility */
 void *shm_unused2; /* ditto - used by DIPC */
 void *shm_unused3; /* unused */
};

在上文中我们就曾学习过,在内核层面上,为了帮助不同的进程能找到同一块共享内存,我们有 key存在于共享内存的数据结构对象中,它可以让不同进程确定是否看到的是同一块共享内存

此时问题来了,为什么我没有在你的数据结构中找到 key的信息呢?事实上,我们看不到 key,是因为设计者对其做了相应的封装,它就被保存在了下面这个结构体中:

 struct ipc_perm shm_perm; /* operation perms */

在这里插入图片描述

程序获取共享内存部分数据结构展示:

	printf("获取属性: size: %d, pid: %d, myself: %d, key: 0x%x", \
            ds.shm_segsz, ds.shm_cpid, getpid(), ds.shm_perm.__key);

输出结果如下:

在这里插入图片描述


结语

🌹🌹 system V - 共享内存 的知识大概就讲到这里啦,博主后续会继续更新更多C++ 和 Linux的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Nacos2.24持久化到Postgres数据库适配——详细版】

Nacos2.24持久化到Postgres数据库适配 前言步骤拉取源码添加依赖修改源码编译打包修改配置测试运行 参考 前言 公司基于springboot实现了一套单体框架&#xff0c;目前我负责搭建SpringCloud微服务框架&#xff0c;需要用到nacos&#xff0c;但是由于公司特殊性&#xff0c;na…

1022.从根到叶的二进制之和

目录 一、题目 二、代码 一、题目 二、代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nu…

玩转 VS code 之下载篇

VSCode 简介 Visual Studio Code (简称 VS Code / VSC)&#xff0c;是2015 年由微软公司推出的一款免费开源的现代化轻量级代码编辑器&#xff0c;支持几乎所有主流的开发语言的语法高亮、智能代码补全、GIT 等特性&#xff0c;支持插件扩展等等 可用于 Windows&#xff0c;ma…

等保测评标准和规范有哪些?

等保测评标准和规范的出现&#xff0c;为我国信息安全等级保护制度的建立和健全提供了重要的保障。 作为信息安全领域的重要评估标准&#xff0c;等保测评旨在通过对信息系统、网络安全设备和安全产品等的安全性能、安全功能、安全管理、安全控制和安全审计等方面的要求进行检查…

【golang】怎样判断一个变量的类型?

怎样判断一个变量的类型&#xff1f; package mainimport "fmt"var container []string{"zero", "one", "two"} func main() {container : map[int]string{0: "zero", 1: "one", 2: "two"}fmt.Printf…

AWS中Lambda集成SNS

1.创建Lambda 在Lambda中&#xff0c;创建名为AWSSNSDemo的函数 use strict console.log(loading function); var aws require(aws-sdk); var docClient new aws.DynamoDB.DocumentClient(); aws.config.regionap-southeast-1;exports.handler function(event,context,cal…

stop job is running for Advanced key-value store

今天虚拟机磁盘撑满了&#xff0c;本来还能凑合运行&#xff0c;结果重启了下&#xff0c;就报了这个 stop job is running for Advanced key-value store (1min 59s / no limit) 解决方式很简单&#xff0c; 1、虚拟机关电源&#xff0c;任务管理器&#xff0c;关闭VM&#x…

LeetCode_03Java_1572. 矩阵对角线元素的和

给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 输入&#xff1a;mat [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;25 解释&#xff1a;对角线的和为&#xff1a;1 5 9 3 7 2…

我们为什么需要API管理系统?

我们为什么需要API管理系统&#xff1f; 随着web技术的发展&#xff0c;前后端分离成为越来越多互联网公司构建应用的方式。前后端分离的优势是一套Api可被多个客户端复用&#xff0c;分工和协作被细化&#xff0c;大大提高了编码效率&#xff0c;但同时也带来一些“副作用”:…

前端接口修改工具 Requestly具体操作

更新于2023年8月12日18:17:56&#xff0c;插件版本可能会变&#xff0c;界面可能会有所变化 插件下载地址&#xff1a;https://chrome.google.com/webstore/detail/requestly-open-source-htt/mdnleldcmiljblolnjhpnblkcekpdkpa 注意&#xff0c;必须用谷歌浏览器&#xff0c;…

Python-OpenCV中的图像处理-模板匹配

Python-OpenCV中的图像处理-模板匹配 模板匹配单对象的模板匹配多对象的模板匹配 模板匹配 使用模板匹配可以在一幅图像中查找目标函数&#xff1a; cv2.matchTemplate()&#xff0c; cv2.minMaxLoc()模板匹配是用来在一副大图中搜寻查找模版图像位置的方法。 OpenCV 为我们提…

强制Edge或Chrome使用独立显卡【WIN10】

现代浏览器通常将图形密集型任务卸载到 GPU&#xff0c;以改善你的网页浏览体验&#xff0c;从而释放 CPU 资源用于其他任务。 如果你的系统有多个 GPU&#xff0c;Windows 10 可以自动决定最适合 Microsoft Edge 自动使用的 GPU&#xff0c;但这并不一定意味着最强大的 GPU。 …

力扣初级算法(数组拆分)

力扣初级算法&#xff08;数组拆分&#xff09; 每日一算法&#xff1a; 力扣初级算法&#xff08;数组拆分&#xff09; 学习内容&#xff1a; 1.问题描述 给定长度为 2n 的整数数组 nums &#xff0c;你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), …, (an, bn) …

leetcode 6914. 翻倍以链表形式表示的数字

给你一个 非空 链表的头节点 head &#xff0c;表示一个不含前导零的非负数整数。 将链表 翻倍 后&#xff0c;返回头节点 head 。 示例 1&#xff1a; 输入&#xff1a;head [1,8,9] 输出&#xff1a;[3,7,8] 解释&#xff1a;上图中给出的链表&#xff0c;表示数字 189 。返…

ubuntu下FFmpeg安装和使用以及CMakeLists.txt模板

sudo apt install ffmpeg sudo apt-get install libavfilter-devcmakelist模板 CMakeLists.txt cmake_minimum_required(VERSION 3.16) project(ffmpeg_demo)# 设置ffmpeg依赖库及头文件所在目录&#xff0c;并存进指定变量 set(ffmpeg_libs_DIR /usr/lib/x86_64-linux-gnu) …

Springboot MultipartFile文件上传与下载

yml文件配置是否可以上传及上传附件大小 servlet:multipart:# 允许文件上传enabled: true# 单个文件大小max-file-size: 20MB# 设置总上传的文件大小max-request-size: 50MB /*** param files* param request* Description 上传文件* Throws* Return java.util.List* Date 202…

prometheus监控k8s服务并告警到钉钉

一、监控k8s集群 要监控k8s集群需要使用到以下服务用于收集监控的资源信息&#xff0c;node_exporter用于监控k8s集群节点的资源信息&#xff0c;kube-state-metrics用于监控k8s集群的deployment、statefulset、daemonset、pod等的状态&#xff0c;cadvisor用于监控k8s集群的p…

关于Linux文件系统只读问题的修改笔记

1.问题 2. 原因 系统异常关机或者代码修改错误导致硬盘挂载出现问题开启只读模式&#xff0c;但是重启有时候可以解决。 3.解决方法 1. mount查看那个挂载的硬盘出现问题(ro标识只读) mount | grep ro2.找到硬盘&#xff0c;重新挂载即可 sudo mount -o remount,rw /sys/f…

基于Googlenet深度学习网络的人员行为动作识别matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 1. 原理 1.1 深度学习与卷积神经网络&#xff08;CNN&#xff09; 1.2 GoogLeNet 2. 实现过程 2.1 数据预处理 2.2 构建网络模型 2.3 数据输入与训练 2.4 模型评估与调优 3. 应用领域…

python技术栈 之 单元测试中mock的使用

一、什么是mock&#xff1f; mock测试就是在测试过程中&#xff0c;对于某些不容易构造或者不容易获取的对象&#xff0c;用一个虚拟的对象来创建以便测试的测试方法。 二、mock的作用 特别是开发过程中上下游未完成的工序导致当前无法测试&#xff0c;需要虚拟某些特定对象…