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

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

下面我们将代码运行起来测试一下:

22666ce1c4b44844b233a167f36444c9.png71f7a0af3448453cafe9f6c890b2e700.png


我们将程序运行起来发现并没有问题,下面我们查看共享内存是否创建成功,ipcs这个命令可以显示出三条资源:

d12f94b447334b4883853acb0c0d9d3c.png

第一条资源为消息队列,第二条资源为共享内存段,第三个为共享内存核心数组,我们主要看第二条,可以看到我们创建的1024大小的共享内存创建成功了。当然我们可以只查第二条,命令是ipcs -m :

0cf9fceb6dd042cdad79fc8173ee3ea7.png

下面我们讲一下上面所代表的意思,key就像文件的inode一样,而shmid就像文件的fd一样shmid才是操作共享内存所需要的核心数据。owner是谁创建的,perms是权限,nattch是与这个共享内存的连接数。下面我们在讲一下删除一个共享内存的命令:ipcrm -m +shmid(刚刚讲过shmid是用来操作共享内存的,与文件的fd作用一样):

fea89b013daf48dc8350c35e91aaa804.png


我们成功的删除了刚刚创建的共享内存。我们接着代码往下写,创建了共享内存后可以让客户端往服务端写一些东西,然后退出的时候需要删除共享内存,我们先来看看如何删除共享内存:


6cf9ba670d6d4976ac90f9f1c2b7382c.png

利用系统调用删除共享内存需要shmctl函数,第一个参数就是共享内存的shmid,第二个参数是指令,也就是说对共享内存做什么操作,我们看看指令有哪些:

54320a79571b40c88b37acade72fcf49.png

常见的指令有这么几个,而IPC_RMID就是真正删除共享内存的操作,第一个IPC_STAT是获取共享内存的属性,而第三个参数是一个共享内存的结构体的指针可以查看共享内存对应的属性:

f3048b36cd304cfcb8a2f462cdb6ac26.png


下面我们就写一个删除共享内存函数:

void delshm(int shmid)
{
    int n = shmctl(shmid,IPC_RMID,nullptr);
    assert(n!=-1);
    (void)n;
}



因为我们删除共享内存的时候不关心它的属性,所以我们直接设为空即可。

a96c0bc32e0645899501cfb28937715a.png

下面我们给大家演示一下查看共享内存的属性:

f881024ce4a54382bcb7e5f03503cab5.pngfecc2836a9974f91a988c559050d39c3.png


下面我们可以在创建共享内存的时候将权限也设置好:

int creatShm(key_t k,int size)
{
    umask(0);
    return createShmHelper(k,size,IPC_CREAT|IPC_EXCL|0666);
}

下面我们要将创建出来的共享内存与进程关联起来,要关联得需要shmat函数:

fcd58f993b9e4031a9292ead4926d2fd.png


第一个参数我们都知道,第二个参数的意思是可以指定将共享内存挂接到指定的地址处(在这里可以设为nullptr,nullptr后操作系统会自己选择合适的地址挂接),第三个参数是设置共享内存是只读的还是什么其他的权限(我们可以设为0,设为0默认是可读可写)

char* attachShm(int shmid)
{
    char* start = (char*)shmat(shmid,nullptr,0);
    return start;
}


4ab9f95c02ed487f979ec36f03d17e95.pngf873ed45566842c4841cc1678166e2de.png


当我们将进程和共享内存关联后,下一步就是退出前将他们去关联,去关联同样也需要函数,这个函数是shmdt:

ce17f85f1cab4b009dfc8ce35f42190e.png

这个函数的参数我们已经讲过了,就是刚刚关联时候给我们返回的那个地址,所以我们可以直接写代码了:

void detachShm(char* start)
{
    int n = shmdt(start);
    assert(n!=-1);
    (void)n;
}


32b0a1a194b249f58cb2c7707c341e48.pngcfe02bf9a9964f2f8e44e18ad3da95d1.png


以上内存的所有点我们就讲完了,下面我们通过一个类封装一下让客户端和服务端的代码可以少一些:

#define SERVER 1
#define CLIENT 0
class Init
{
public:
    Init(int type)
    {
        key_t k = getKey();
        if (type==SERVER)
        {
            shmid = creatShm(k,gsize);
        }
        else 
        {
            shmid = getShm(k,gsize);
        }
        start = attachShm(shmid);
    }
    char* getStart()
    {
        return start;
    }
    ~Init()
    {
        detachShm(start);
        if (type==SERVER)
        {
            delShm(shmid);
        }
    }
private:
    char* start;
    int type;
    int shmid;
}


通过以上类的封装,我们的客户端和服务端就能简化为以下这样:

1d9b3b51f466491cb82d8746542c6b89.pnge4461a60fd354872a4b29cfadd7f35d5.pngf3238f4350fe403bbffafc5615dbb37a.png1b8ab36015514316a6e03014c8a6d6bd.pngf9fb260e1cce4ff08ec0ab54c5b5517c.png

我们可以看到当我们一开始两个端口都运行的时候有两个进程链接在共享内存上,当客户端指令输入完成退出后就只剩下服务端,当服务端也退出后那么连接数就为0了。

以上就是我们共享内存的所有内容,学了共享内存要知道共享内存是进程间通信的几种方式中访问速度最快的。


总结



使用ipcrm -m 命令删除指定共享内存后,是不会直接释放共享内存的,因为共享内存的生命周期是随操作系统的,只有共享内存当前的映射链接数为0才会被删除释放。


使用ipcrm -a 可以删除所有进程间通信资源(a代表all也就是全部的意思)


ipcrm -m删除共享内存,-q删除消息队列,-s删除信号量


共享内存实现实现通信的原理是因为所有进程操作映射同一块物理内存。


共享内存的操作是非进程安全的,多个进程同时对共享内存读写是有可能造成数据的交叉写入或读取,造成数据混乱。


共享内存的删除操作并非是直接删除,而是拒绝后续映射,只有在当前映射链接数为0的时候表示没有进程访问了,才会真正的被删除。


共享内存生命周期随内核,只要不删除,就一直存在于内核中,除非重启系统或者手动删除。

目录
相关文章
|
5天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
28 4
linux进程管理万字详解!!!
|
3天前
|
算法 Linux 开发者
深入探究Linux内核中的内存管理机制
本文旨在对Linux操作系统的内存管理机制进行深入分析,探讨其如何通过高效的内存分配和回收策略来优化系统性能。文章将详细介绍Linux内核中内存管理的关键技术点,包括物理内存与虚拟内存的映射、页面置换算法、以及内存碎片的处理方法等。通过对这些技术点的解析,本文旨在为读者提供一个清晰的Linux内存管理框架,帮助理解其在现代计算环境中的重要性和应用。
|
5天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
28 4
|
6天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
7天前
|
消息中间件 存储 Linux
|
8天前
|
存储 缓存 监控
|
14天前
|
运维 Linux
Linux查找占用的端口,并杀死进程的简单方法
通过上述步骤和命令,您能够迅速识别并根据实际情况管理Linux系统中占用特定端口的进程。为了获得更全面的服务器管理技巧和解决方案,提供了丰富的资源和专业服务,是您提升运维技能的理想选择。
15 1
|
6天前
|
缓存 算法 Linux
Linux内核中的内存管理机制深度剖析####
【10月更文挑战第28天】 本文深入探讨了Linux操作系统的心脏——内核,聚焦其内存管理机制的奥秘。不同于传统摘要的概述方式,本文将以一次虚拟的内存分配请求为引子,逐步揭开Linux如何高效、安全地管理着从微小嵌入式设备到庞大数据中心数以千计程序的内存需求。通过这段旅程,读者将直观感受到Linux内存管理的精妙设计与强大能力,以及它是如何在复杂多变的环境中保持系统稳定与性能优化的。 ####
13 0
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
331 0
|
14天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
27 1