进程通信——共享内存

news2024/9/22 3:45:59

文章目录

  • 1.基本认识
    • 1.1 概念介绍
    • 1.2主要原理
  • 2.使用方法
    • 2.1创建共享内存shmget
      • 2.1.1 shmget
      • 2.1.2 ftok
    • 2.2映射地址空间shmat
    • 2.3 访问共享内存
    • 2.4 同步和互斥
  • 3.接口封装
    • 3.1 创建shm_create
    • 3.2 映射shm_connect
    • 3.3 多进程共享内存

共享内存是一种机制,也是进程间进行通信的一种方式
https://zhuanlan.zhihu.com/p/698506822

1.基本认识

1.1 概念介绍

不同进程的资源通常是独立的,他们所占用的内存互相独立,不可互相访问。
共享内存允许多个进程访问同一块内存区域,从而实现数据的共享和交换。是一种高效的进程通信方法。

在共享内存中,多个进程可以将同一块物理内存,映射到它们各自的虚拟地址中,使它们可以直接读写该内存的内容,而无需通过消息传递等其它通信方式,也就是“完全无需额外的拷贝”。这种直接的内存访问,使得数据交换更高效。

1.2主要原理

要理解共享内存,首先要理解“虚拟内存”这一概念。

虚拟内存是进程直接操作的地址,不同进程可以存在相同的虚拟内存地址,因为实际所代表的物理地址并不相同

每个进程内的虚拟地址是连续的,但实际映射在物理地址上,却不是连续的。

通常来说各进程之间不会共用物理内存地址,如下图所示:
在这里插入图片描述
进程A和进程B各自的虚拟内存,分别映射在实际物理内存的不同区域上。

那么,共享内存就是改变这种映射关系,让不同的进程“共用物理内存”。如下图所示:
在这里插入图片描述
这个时候,进程A的第3块虚拟内存,与进程B的第1块虚拟内存,就指向同一块物理内存了。

也就是它们共享内存了。之后其中一个改写了这块内存的内容,另一个就可以直接读到,省去了中间(系统内核)的数据拷贝。这就是所谓“共享内存效率最高”的原因。

但从中我们不难看出,共享内存也是有缺点的,那就是大家都是读写同一块内存,很容易冲突。所以共享内存通常还需要搭配其它同步机制使用。

2.使用方法

共享内存的使用并不难,就是改变内存映射,获取到同一个指向共享内存的地址,然后读写数据。

2.1创建共享内存shmget

第一步是创建一个共享内存区域,并分配一块内存来存储数据。

2.1.1 shmget

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

/***********************************
* @para key 共享内存的键值,用于标识共享内存段。通常使用 ftok 函数生成键值。
* @para size 共享内存段的大小,以字节为单位
* @para shmflg 共享内存的标志位,用于指定创建共享内存的权限和行为
* @return 成功时,返回共享内存的标识符(即共享内存的ID)
* 		  失败时,返回-1,并设置相应的错误码
* 
*********************************/
int shmget(key_t key, size_t size, int shmflg);

//example
key_t key = ftok(".", 123); //详见下一节
int shmid = shmget(key, 1024, IPC_CREAT | 0666);

2.1.2 ftok

上述出现了一个 ftok 函数,这个函数返回了一个 key_t

这个有什么作用呢?其实,这个 key 是不同进程间使用同一片物理内存的关键。如果要进行共享,就大家都得使用同一个 key。否则,系统如何知道哪几个进程之间要共享呢。

而 ftok 则是使用一个“路径(文件或目录)”加一个“立即数”,来产生一个 key。只要大家的这两个参数相同,计算出来的 key 就是一致的。

其原型如下:

#include <sys/types.h>
#include <sys/ipc.h> 
key_t ftok(const char *pathname, int proj_id);

参数:
pathname:一个存在的文件路径名,用于生成键值。通常选择一个已经存在的文件。
proj_id:一个整数,用于区分不同的IPC资源。通常选择一个非零的整数。

返回值:
如果成功,返回一个键值(key)。
如果失败,返回-1,并设置相应的错误码。

关于ftok,还有几个要点:

  • ftok 的路径可以随便设置,但必须是实际存在的
  • ftok 只是想取文件 inode 这个唯一数值,和文件权限无关
  • proj_id 在一些系统(如 UNIX)上,实际取值是1到255。

为什么对 ftok 说那么多,因为这个 key 对很多进程间通信都是一个关键。不只是共享内存,其它诸如消息队列、信号量之类的方法,也会用到。

2.2映射地址空间shmat

第二步就是,将创建出的共享内存空间,映射到本进程的虚拟地址空间。
映射使用的是 shmat,原型如下:

参数:
shmid:共享内存的标识符(即共享内存的ID),由shmget函数返回
shmaddr:指定共享内存段附加到当前进程地址空间的地址。通常设置为 NULL,表示由系统自动选择一个合适的地址
shmflg:共享内存的标志位,用于指定附加共享内存的权限和行为

返回值:
成功时,返回指向共享内存段附加地址的指针。
失败时,返回 -1,并设置相应的错误码。

例子:
#include <sys/types.h>
#include <sys/shm.h>
char *shmaddr = shmat(shmid, NULL, 0);

2.3 访问共享内存

这一步比较简单,就是向共享内存(也可以理解为自己的地址空间)写数据和读数据。

memcpy(shmaddr, source_buff, source_length); //写 
memcpy(target_buff, shmaddr, target_length); //读

2.4 同步和互斥

之前提到过共享内存的不足。由于多个进程可以同时访问共享内存,需要使用同步和互斥机制来确保数据的一致性和正确性。常见的同步机制包括信号量、互斥锁和条件变量等。在这里就不再展开了。

3.接口封装

3.1 创建shm_create

#include <sys/types.h>
#include <sys/ipc.h> 
key_t ftok(const char *pathname, int proj_id);
#define KEY_NUM 126
#define FILE_PATH "./share.txt"

int shm_create_with_key(const char *filepath, int len, int key_num)
{
	key_t key = ftok(filepath, key_num);
	if(key < 0)
	{
		printf("create key error!\n");
		return key;
	}
	int shmid = shmget(key, len, IPC_CREATE|0666);//666代表可读可写
	if(shmid < 0)
	{
		return shmid;
		printf("create share mem error!\n")
	}
	return shmid
}

int shm_create(int len)
{
	return shm_create_with_key(FILE_PATH, len, KEY_NUM);
}

3.2 映射shm_connect


char* shm_connect(int shm_id)
{
	char *mem = shmat(shm_id, NULL, 0);
	if(mem < 0)
	{
		printf("shmat error!\n");
		return mem;
	}
	return mem;
}

3.3 多进程共享内存

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

#define KEY_NUM 126
#define FILE_PATH "./share.txt"

//使用文件路径作为共享内存
int shm_create_with_key(const char *filepath, int len, int key_num)
{
	key_t key = ftok(filepath, key_num);
	if(key < 0)
	{
		printf("create key error!\n");
		return key;
	}
	int shmid = shmget(key, len, IPC_CREAT|0666);//666代表可读可写
	if(shmid < 0)
	{
		return shmid;
		printf("create share mem error!\n");
	}
	return shmid;
}

int shm_create(int len)
{
	return shm_create_with_key(FILE_PATH, 100, KEY_NUM);
}

char* shm_connect(int shm_id)
{
	char *mem = (char*)shmat(shm_id, NULL, 0);
	if(mem < 0)
	{
		printf("shmat error!\n");
		return NULL;
	}
	return mem;
}

int main()
{
    int shm_id = shm_create(10);
    if(shm_id < 0)
    {
        printf("shm_create error!\n");
        return -1;
    }   
    char *mem = shm_connect(shm_id);
    if(!mem)
    {
        printf("shm_connect error!\n");
        return -1;
    }
    int i = 10;
    while (--i)
    {
        printf("%s\n", mem);
        sleep(1);
    }

    shmdt(mem);
    return 0;
}

#include <sys/types.h>
#include <sys/ipc.h> 
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "string.h"

#define KEY_NUM 126
#define FILE_PATH "./share.txt"

int shm_create_with_key(const char *filepath, int len, int key_num)
{
	key_t key = ftok(filepath, key_num);
	if(key < 0)
	{
		printf("create key error!\n");
		return key;
	}
	int shmid = shmget(key, len, IPC_CREAT|0666);//666代表可读可写
	if(shmid < 0)
	{
		return shmid;
		printf("create share mem error!\n");
	}
	return shmid;
}

int shm_create(int len)
{
	return shm_create_with_key(FILE_PATH, 100, KEY_NUM);
}


char* shm_connect(int shm_id)
{
	char *mem = (char*)shmat(shm_id, NULL, 0);
	if(mem < 0)
	{
		printf("shmat error!\n");
		return NULL;
	}
	return mem;
}

int main()
{
    int shm_id = shm_create(10);
    if(shm_id < 0)
    {
        printf("shm_create error!\n");
        return 0;
    }   
    char *mem = shm_connect(shm_id);
    if(!mem)
    {
        printf("shm_connect error!\n");
        return 0;
    }
    //初始化
    memcpy(mem, "hello", 6);
    int i = 0;
    while (i<10)
    {
        mem[0] = '1'+i;
        ++i;
        sleep(1);
    }

    shmdt(mem);
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot中@SchedulerLock注解实现定时任务中分布式锁的使用

背景 在SpringBoot项目中经常会去写一些定时任务&#xff0c;但是当我们的服务的实例部署多个的情况下&#xff0c;那么每个实例中的定时任务都会执行一遍&#xff0c;这显然不是我们想要的&#xff0c;我们只想让它执行一次。在没有引入像xxl-job之类的分布式任务调度框架的前…

BIRTV2024圆满落幕,中科极光9万流明点亮观影新体验

8月21日,第三十一届北京国际广播电影电视展览会BIRTV 2024隆重开幕。展示广电先进技术设备和发展成果&#xff0c;引领中国广播影视技术发展潮流&#xff0c;全媒体、超高清、强智能&#xff0c;带着本届BIRTV理念&#xff0c;中科极光携RGB三色激光光源升级解决方案LSS-AM系列…

【大模型】LangChain基础学习

前言:LangChain是一个用于构建端到端语言模型应用的框架 目录 1. 基础知识2. 基本使用2.1 安装2.2 启动示例2.3 使用prompt2.4 输出解析器 3. 相关应用3.1 RAG 参考文献 1. 基础知识 六大组件 模型&#xff08;Models&#xff09;&#xff1a;包含各大语言模型的LangChain接口…

2024年“羊城杯”粤港澳大湾区网络安全大赛 PWN部分

2024年“羊城杯”粤港澳大湾区网络安全大赛 PWN部分 Author&#xff1a;Ns100kUp From&#xff1a;极安云科-服务中心 Data&#xff1a;2024/08/27 Copyright:本内容版权归属极安云科&#xff0c;未经授权不得以任何形式复制、转载、摘编和使用。培训、环境、资料、考证 公众号…

LabVIEW开发高温摩擦试验机

采用LabVIEW软件开发高温摩擦试验机&#xff0c;特别是在航空轴承摩擦学性能测试中的应用。通过详细介绍系统的设计、组成、工作原理及其实现&#xff0c;展示了该系统在动态监测轴承状态参数中的关键作用&#xff0c;以及其在提高测试效率和准确性方面的优势。 项目背景 轴承…

AMBA-CHI协议详解(八)

AMBA-CHI协议详解&#xff08;一&#xff09; AMBA-CHI协议详解&#xff08;二&#xff09; AMBA-CHI协议详解&#xff08;三&#xff09; AMBA-CHI协议详解&#xff08;四&#xff09; AMBA-CHI协议详解&#xff08;五&#xff09; AMBA-CHI协议详解&#xff08;六&#xff09…

FTP(File Transfer Protocol,文件传输协议)

FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09;是一种用于在网络上交换文件的协议&#xff0c;它定义了文件传输时使用的命令和响应。FTP是最古老的互联网协议之一&#xff0c;至今仍被广泛使用。以下是FTP的一些关键特点和信息&#xff1a; 工作…

学生用什么类型投影仪比较好?2024开学季最值得买的装备当贝X5S投影仪

9月开学季来临&#xff0c;全国的学生们都将陆续开学&#xff0c;暑假结束接下来也只有周末的时间可以让孩子劳逸结合&#xff0c;怎么样才能在忙碌的学业中既能轻松学到知识又能浏览到大量的信息&#xff1f;给孩子看纪录片就是一个好方法&#xff0c;现在比较流行周末家长给孩…

spring security 相关过滤器

Spring Security 提供了 30 多个过滤器。默认情况下Spring Boot 在对 SpringSecurity 进入自动化配置时&#xff0c;会创建一个名为 SpringSecurityFilerChain 的过滤器&#xff0c;并注入到Spring容器中&#xff0c;这个过滤器将负责所有的安全管理&#xff0c;包括用户认证、…

22行为型设计模式——解释器模式

一、解释器模式 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种行为型设计模式&#xff0c;主要用于解析和解释特定的语言或表达式。它的核心思想是为语言中的每种语法规则定义一个解释器&#xff0c;通过这些解释器将语言的表示形式转换为可执行的操作。解释器…

240831-RAG新利器之Kotaemon的安装与配置

A. 用户界面 该项目既可以作为功能性 RAG UI&#xff0c;既可以用于对文档进行 QA 的最终用户&#xff0c;也可以用作想要构建自己的 RAG 管道的开发人员。对于最终用户&#xff1a; - 一个干净且简约的用户界面&#xff0c;用于基于RAG的QA。 - 支持 LLM API 提供程序&#xf…

最小栈

最小栈 这题难就难在要能在常数时间内检索到最小元素。 单纯用一个变量记录最小值是无法实现常数时间内获取最小元素的&#xff0c;这个时候我们根据栈的特性&#xff0c;另开一个辅助栈&#xff0c;存储我们的栈里每个时刻的最小值。代码&#xff1a; class MinStack {stac…

idea的全局配置

这样一来&#xff0c;每次创建新项目完就不用每次改配置了

内存管理篇-16二级页表工作原理

1.修正上节课的转换图 上节课的页表的一级页表其实并不完全正确&#xff0c;一般虚拟页帧和物理页帧号不会都占用实际字段&#xff0c;这样毕竟很浪费内存。 2.再分析一下页表的开销情况&#xff1a; 一级页表&#xff1a;以4KB物理页为映射单位&#xff0c;每个进程4MB的虚…

【Python】家庭用电数据的时序分析

Household Electricity Consumption | Kaggle 目录 数据简介 探索分析 数据清洗 用电占比 趋势分析 序列分解 周期分析 周期分解 分析小结 数据简介 240000-household-electricity-consumption-records数据集包含了一个家庭6个月的用电数据&#xff0c;收集于2007年1…

HTB-Appointment(SQL注入-万能钥匙)

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解Appointment靶场&#xff0c;这一章节 我们涉及到一些web安全的相关知识 渗透过程 信息搜集 我们通过端口扫描&#xff0c;得知对方开启了http80端口思路&#xff1a;尝试扫描下敏感目录 目录扫描(gob…

PTH哈希传递攻击

PTH哈希传递攻击&#xff08;Pass The Hash&#xff09; 一、PTH简介 1、攻击原理 在使用 NTLM 身份验证的系统或服务上&#xff0c;用户密码永远不会以明文形式通过网络发送。 Windows 上的应用程序要求用户提供明文密码&#xff0c;然后调用 LsaLogonUser 类的 API&#x…

AR 眼镜之-系统通知定制(通知中心)-实现方案

目录 &#x1f4c2; 前言 AR 眼镜系统版本 系统通知定制 1. &#x1f531; 技术方案 1.1 技术方案概述 1.2 实现方案 1&#xff09;通知弹窗消失 2&#xff09;通知中心显示 2. &#x1f4a0; 通知弹窗消失 2.1 通知弹窗显示时长到期后自动消失 2.2 将通知添加到通知…

vue3中ref绑定的节点顺序错乱

问题复现 眨眼睛这个是修正过了的&#xff0c;小友的应该是ref直接绑定navigationTextList对吧&#xff0c; 按正常想法肯定是既然这个数组会动态更新&#xff0c;我只需要index不就能确定是哪个节点啦&#xff0c;倘若只是静态数据应该不会有什么问题&#xff0c; ⚠️但如果出…

想了个创业的点子问老婆,她说你这不就是外包公司吗

年近35&#xff0c;老在想着万一毕业了咋整&#xff0c;其他的技能也不会&#xff0c;只能去“吉祥三保”、“铁人三项”了&#xff0c;但是吧又不甘心这十来年的“手艺”&#xff0c;又想着这几年大环境下那么多失业的同行&#xff0c;是不是也都有这方面的需求&#xff0c;于…