【Linux】进程间通信之共享内存(上)

简介: 【Linux】进程间通信之共享内存(上)

前言



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


一、共享内存的实现原理



7c28f9a0dbd846b68d18844805d2cce0.png


我们以上图为例,A和B是两个进程,他们都有自己的进程地址空间,进程地址空间经过页表映射到物理内存中,而共享内存是什么呢?就是有一个机制在物理内存中直接开好一块内存,这一块内存经过页表的映射到进程地址空间中的共享区(共享区在堆区和栈区之间),然后把共享区这块空间的起始地址返回给用户,两个进程进行同样的工作不就实现了让不同的进程看到同一份资源吗,那么如何让这两个进程取消关联呢?其实很简单,如下图:

e220ae7cb1a84c0aa6b633e883d13d8c.png



要取消两个进程间的关系只需要修改页表让进程地址空间不再通过页表的映射找到共享内存,并且将开好的空间释放掉,这就完成了进程间的取消关联。以上就是共享内存的基本原理。


二、实现共享内存的代码



首先我们创建所需要的文件,比如这里我创建了shmclient.cc和shmserver.cc以及makefile,然后我们需要用makefile帮我们创建两个可执行程序:

.PHONY:all
all:shmclient shmserver
shmclient:shmclient.cc
  g++ -o $@ $^ -std=c++11
shmserver:shmserver.cc
  g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
  rm -f shmclient shmserver


当然我们还需要一个存放头文件的文件:

c756d33a6074413b9a063a50bb4d019b.png


我们为了防止头文件重复包含所以用了条件编译,下面我们开始正式写代码,在这之前我们需要了解shmget函数,这个函数是用来获取共享内存的:

40319068e5914fa782ee1531ccd6d10b.png

此函数有三个参数,第一个参数key我们稍后讲解,第二个参数size就是要开多大的共享内存,第三个参数开的模式,IPC_CREAT的意思是创建一个共享内存,如果共享内存不存在,就创建,如果已经存在了就获取已经存在的共享内存并返回。IPC_EXCL不能单独使用,要配合IPC_CREAT使用,使用方式是(IPC_CREAT | IPC_EXCL),这两个组合在一起就是创建一个共享内存,如果共享内存不存在,就创建一个新的共享内存,如果已经存在了共享内存,就立马出错返回,那么这有什么意义呢?意义就是保证给我们创建的共享内存一定是最新的没有被使用过。


下面我们来看看shmget函数的返回值:

157236ff86434f8ab0fd449cccbe3d4b.png


如果我们创建成功了就给我们返回一个共享内存的标志,如果错误则返回-1.现在我们来讲讲第一个参数key是什么,我们可以看到这个参数的类型key_t,而这个参数实际上我们是需要另一个函数ftok获取的,下面我们来看看ftok函数:

d1180925253c4f058f387560595c4c76.png

ftok这个函数的第一个参数是路径,第二个参数是一个int类型的id,这两个参数是用户去填的,ftok函数会结合路径和id转化出一个很难被重复的key值,由于系统中一定会同时存在多个共享内存,所以共享内存不是我们想的那样只要在内存中开辟空间即可,而是系统为了管理共享内存,会构建结构体来描述共享内存,所以共享内存 = 共享内存的内核数据结构 + 真正开辟的内存空间。下面我们用画图的方式解释一下这里的关系:

d29122a19cb64dc69a44b12d42c3d745.png


中间的4个共享内存结构体是被系统所管理的,红色的共享内存是被进程A开辟的,那么如何让B进程也指向A开辟的这个共享内存呢,只需要让他们两个进程都用同一个路径和同一个id这样就生成了同样的key值,有了这个值B进程就能指向A开辟的那个共享内存了。


理解了以上的知识我们就可以直接写代码了,先将所有的头文件包好,因为两个进程都需要同样的路径和id所以我们直接define一下:

b789d959739d4636a2cac3f92932b956.png

我们直接将路径定义为一个.,一个点就代表是在当前路径,那么到时候创建共享内存的时候就会创建在当前当前路径了。下面我们直接写一个获取key的函数:

在用ftok函数之前我们先看一下此函数的返回值:


05f2ed9c4c6f4c8eaae2f480c380e859.png


如果成功就返回已经创建好的key值,如果失败则返回-1.

#ifndef __COMM__HPP__
#define __COMM__HPP__
#include <iostream>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
using namespace std;
#define PATHNAME "."
#define PROJID 0x6666
key_t getKey()
{
    key_t k = ftok(PATHNAME,PROJID);
    if (k==-1)
    {
        cerr<<errno<<" : "<<strerror(errno)<<endl;
        exit(1);
    }
    return k;
}


有了key后下一步我们就可以开始创建共享内存了,从我们刚刚画的图可以看到,一定是有一个进程先创建了共享内存,然后另一个进程去找获取刚刚创建的共享内存,所以我们下一步就是在服务端创建一个共享内存:

b8b37a9073f14649bc2131e883d3360e.png 首先我们先用一个全局变量来控制共享内存的大小,然后直接用两个函数封装创建共享内存和打开共享内存:

static int createShmHelper(key_t k,int size,int flag)
{
    int shmid = shmget(k,gsize,flag);
    if (shmid==-1)
    {
        cerr<<errno<<" : "<<strerror(errno)<<endl;
        exit(2);
    }
    return shmid;
}
int creatShm(key_t k,int size)
{
    return createShmHelper(k,size,IPC_CREAT|IPC_EXCL);
}
int getShm(key_t k,int size)
{
    return createShmHelper(k,size,IPC_CREAT);
}


第一个静态函数就是我们创建共享内存的步骤,flag是我们要怎么创建的选项,第一次创建必须是一个全新的没有使用过的,这个给服务端用,第二个是打开已有的共享内存是给客户端用的,然后我们在客户端和服务端也把代码写完整:

233f995f8a4242b583911d5f49cef1d6.png6a03a53ff2f349c289ba953c03344bb1.png


目录
相关文章
|
8天前
|
缓存 Java Linux
如何解决 Linux 系统中内存使用量耗尽的问题?
如何解决 Linux 系统中内存使用量耗尽的问题?
|
21天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
74 4
linux进程管理万字详解!!!
|
3天前
|
算法 调度 开发者
深入理解操作系统:从进程管理到内存分配
本文旨在为读者提供一个深入浅出的操作系统知识之旅,从进程管理的基础概念出发,探索内存分配的策略与技巧。我们将通过实际代码示例,揭示操作系统背后的逻辑与奥秘,帮助读者构建起对操作系统工作原理的直观理解。文章不仅涵盖理论知识,还提供实践操作的指导,使读者能够将抽象的概念转化为具体的技能。无论你是初学者还是有一定基础的开发者,都能在这篇文章中找到有价值的信息和启发。
|
11天前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
53 8
|
8天前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
8天前
|
缓存 Linux
如何检查 Linux 内存使用量是否耗尽?
何检查 Linux 内存使用量是否耗尽?
|
18天前
|
算法 Linux 开发者
深入探究Linux内核中的内存管理机制
本文旨在对Linux操作系统的内存管理机制进行深入分析,探讨其如何通过高效的内存分配和回收策略来优化系统性能。文章将详细介绍Linux内核中内存管理的关键技术点,包括物理内存与虚拟内存的映射、页面置换算法、以及内存碎片的处理方法等。通过对这些技术点的解析,本文旨在为读者提供一个清晰的Linux内存管理框架,帮助理解其在现代计算环境中的重要性和应用。
|
20天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
57 4
|
21天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
1天前
|
存储 算法 安全
深入理解Linux内核的内存管理机制
本文旨在深入探讨Linux操作系统内核的内存管理机制,包括其设计理念、实现方式以及优化策略。通过详细分析Linux内核如何处理物理内存和虚拟内存,揭示了其在高效利用系统资源方面的卓越性能。文章还讨论了内存管理中的关键概念如分页、交换空间和内存映射等,并解释了这些机制如何协同工作以提供稳定可靠的内存服务。此外,本文也探讨了最新的Linux版本中引入的一些内存管理改进,以及它们对系统性能的影响。
下一篇
无影云桌面