Linux进程通信——共享内存(上)

简介: Linux进程通信——共享内存(上)

共享内存

原理与概念

两个进程的PCB创建虚拟地址空间然后映射到物理内存中,每个进程因为是独立的,所以在物理内存中的地址也不同。

那么共享内存是怎么做到的呢?

首先先在物理内存中申请一块内存。

然后讲这块内存通过页表映射分别映射到这两个进程的虚拟地址空间内,让这两个进程都能看到这块内存。(这里也称为进程和共享内存挂接)

最后如果不想通信了:

取消进程和内存的映射关系(去关联)

释放内存(释放共享内存)

理解:

a.这里和原本C语言当中的maclloc函数开辟空间不同,我们的目的是要让两个进程同时看到这块内存。

b.进程通信的这个申请一块共享内存是专门设计出来的,用来IPC。

c.共享内存是一种通信的方式,所有想通信的进程都可以用。

d.OS一定可能会存在很多的共享内存。

概念就是:通过让不同进程看到同一个内存块的方式就叫做共享内存。

函数接口的介绍与使用

shmget

创建共享内存接口:

首先来看第三个参数:

这里是通过位图的方式(二进制标志位)传参。

IPC_CREAT 如果不存在,创建,如果存在,就获取共享内存的位置。

IPC_EXCL 这个选项无法单独使用,必须结合IPC_CREAT使用,一起使用代表的含义是,如果不存在就创建,存在就会返回错误。(也就是说如果创建成功,他一定是一个新的共享内存——shm)

第二个参数是创建shm的大小。

返回值:

如果成功就返回一个共享内存的合法标识符,失败就返回-1。(这个和文件操作符完全不同,不是一个体系)

第一个参数:

这个是让多个进程看到同一份shm的关键。能进行唯一标识。

这个值是怎么来的呢?

用这个函数生成:

将一个合法路径(字符串)和字符数据通过某种算法组合来进行计算出key值,然后返回key。

失败了返回-1。

那么,怎么样才能让两个进程看到同一份共享内存呢?

在两个进程中如果传入到ftok中的两个参数相同,返回的key也相同,其中一个进程通过shmget接口创建共享内存,另一个接口通过shmget接口接收共享内存的位置,这样两个进程就能看到同一份资源了。

我们要利用接口让两个进程实现通信,首先创建两个.cc的文件,一个头文件.hpp。

因为两个进程都要创建/获取共享内存,所以获取key等等操作在头文件更方便。

#ifndef _COMM_HPP_
#define _COMM_HPP_
#include<iostream>
#include<cassert>
#include<cstring>
#include<cerrno>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cstdlib>
#define PATHNAME "."//ftok的第一个参数,是一个合法路径
#define PROJ_IO 0X666//ftok的第二个参数
key_t getkey()
{
    key_t k = ftok(PATHNAME, PROJ_IO);
    if(k < 0)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(1);
    }
    return k;
}
#endif

然后来测试一下这个函数:

两个进程都调用这个函数:

#include"shm.hpp"
int main()
{
    key_t k = getkey();
    printf("0x%x\n",k);
    return 0;
}

运行之后我们发现两个进程打印的结果key值都是相同的。

key_t的本质就是一个32位的整数。

然后再用shmget去创建和获取共享内存。

int getshmhelper(key_t k, int flags)
{
    int shmid = shmget(k, MAXSIZE, flags);
    if(shmid < 0)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(2);
    }
    return shmid;
}
int getshm(key_t k)//获取共享内存
{
    return getshmhelper(k, IPC_CREAT);//没有就创建,有就获取
}
int createshm(key_t k)//创建共享内存
{
    return getshmhelper(k, IPC_CREAT | IPC_EXCL | 0600);//没有创建,有就报错,这里创建内存需要给对应的权限
}

我们让server去创建一个共享内存,client去拿共享内存中的数据。

这里再次创建共享内存会报错。

那么key的意义是什么呢?

首先清楚,OS一定可能会存在很多共享内存,并且本质就是申请一块空间,能进行唯一性标识最重要。

之前的C语言,malloc开辟n大小的空间的时候,释放时并不需要告诉他释放多大,自己就知道释放掉n个大小的内存,其实这一块内存中OS也要对这块中间做管理,申请了n个大小,并不代表就是n个,因为里面还有对这块内存的属性和数据左储存,比如大小,释放的时候就回去找这个大小。

这里共享内存也是一样的,OS要先描述再组织,才能进行管理,每次申请一块共享内存,OS还会给这块共享内存申请一个数据结构对象。

所以:共享内存 = 物理内存快 + 共享内存的相关属性

OS管理的是对这个共享内存的数据结构对象做管理的。

那么在创建共享内存的时候,如何保证共享内存在OS中是唯一的呢?答案就是key。

key就像餐厅当中的桌号一样,每个都具有唯一性。

其中一个进程创建共享内存,这块区域中有key值,只要另一个进程也看到同一个key就说明能看到同一块内存。

那么怎么找到key 的位置呢?就在共享内存中的数据结构中。

struct shm

{

key_t k;

}

也就是说ftok函数返回的key值其实就是赋值给共享内存数据结构中的key值。

这就是创建key的含义,key是要通过shmget设置进入共享内存属性中的,用来表示该共享内存在内核中的唯一性。

那么用来接收shmget返回值的变量有什么意义呢?

比如说,我们在企业有自己的员工号,企业扩大的时候,变动的是员工号,并不影响我们的身份证号,这时一种解耦的体现。

用来接收shmget返回值的变量和key值互相不干扰。

就像钥匙和锁一样。(fd与inode也是相同的道理)

那么如何查看IPC资源呢?

首先上面的代码在创建共享内存的时候,明明进程已经结束了,但还显示这个资源已被占用,因为共享内存是OS级的,他的生命周期是和OS相同的,要等OS的关机才会释放掉。

这里用 ipcs -m 查看共享内存。

想删除这块共享内存要用 ipcrm -m shmid

这种方法不太好,所以提供了另一个接口。

shmctl

第一个参数就是上面接受创建共享内存函数的返回值,第二个参数是选项,用来控制这个函数做什么,第三个参数是一个数据结构,就是下面的那个:

返回值是shmid,失败返回-1。

这个选项就是删除掉这段共享内存。

void delshm(int shmid)
{
    if(shmctl(shmid, IPC_RMID, nullptr) == -1)
    {
        std::cerr << errno << ":" << strerror(shmid) << std::endl;
        exit(3);
    }
}

这里谁创建的谁进行删除就可以了。

现在还差一步让两个进程与这个共享内存关联。

相关文章
|
12天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
35 1
|
7天前
|
SQL 运维 监控
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
南大通用GBase 8a MPP Cluster Linux端SQL进程监控工具
|
14天前
|
C语言 开发者 内存技术
探索操作系统核心:从进程管理到内存分配
本文将深入探讨操作系统的两大核心功能——进程管理和内存分配。通过直观的代码示例,我们将了解如何在操作系统中实现这些基本功能,以及它们如何影响系统性能和稳定性。文章旨在为读者提供一个清晰的操作系统内部工作机制视角,同时强调理解和掌握这些概念对于任何软件开发人员的重要性。
|
12天前
|
算法 Linux
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
|
13天前
|
Linux 调度 C语言
深入理解操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅,从进程管理的基本概念出发,逐步探索到内存管理的高级技巧。我们将通过实际代码示例,揭示操作系统如何高效地调度和优化资源,确保系统稳定运行。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇了解操作系统深层工作原理的大门。
|
15天前
|
运维 监控 Linux
Linux操作系统的守护进程与服务管理深度剖析####
本文作为一篇技术性文章,旨在深入探讨Linux操作系统中守护进程与服务管理的机制、工具及实践策略。不同于传统的摘要概述,本文将以“守护进程的生命周期”为核心线索,串联起Linux服务管理的各个方面,从守护进程的定义与特性出发,逐步深入到Systemd的工作原理、服务单元文件编写、服务状态管理以及故障排查技巧,为读者呈现一幅Linux服务管理的全景图。 ####
|
20天前
|
缓存 算法 Linux
Linux内核的心脏:深入理解进程调度器
本文探讨了Linux操作系统中至关重要的组成部分——进程调度器。通过分析其工作原理、调度算法以及在不同场景下的表现,揭示它是如何高效管理CPU资源,确保系统响应性和公平性的。本文旨在为读者提供一个清晰的视图,了解在多任务环境下,Linux是如何智能地分配处理器时间给各个进程的。
|
20天前
|
存储 算法 安全
深入理解Linux内核的内存管理机制
本文旨在深入探讨Linux操作系统内核的内存管理机制,包括其设计理念、实现方式以及优化策略。通过详细分析Linux内核如何处理物理内存和虚拟内存,揭示了其在高效利用系统资源方面的卓越性能。文章还讨论了内存管理中的关键概念如分页、交换空间和内存映射等,并解释了这些机制如何协同工作以提供稳定可靠的内存服务。此外,本文也探讨了最新的Linux版本中引入的一些内存管理改进,以及它们对系统性能的影响。
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
5月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
190 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)