【Linux】system V进程间通信--共享内存,消息队列,信号量

目录

共享内存

基本原理

创建共享内存

共享内存创建好后,我们可以查询共享内存,验证一下是否创建成功;

删除共享内存

共享内存的挂接

实现通信

消息队列(了解)

消息队列概念

消息队列接口

操作指令

信号量(了解)

信号量概念

理解信号量

信号量操作


通信的方式有三种:聚焦本地通信的System V ,实现跨主机之间的通信POSIX ,以及基于文件系统的管道通信;

下面是System V的通信方式:

system V IPC提供的通信方式有三种: 共享内存、消息队列、信号量;并且生命周期是随OS的,而不是随进程的,这是所有System V进程间通信的共性;

共享内存

共享内存=内存空间(数据)+共享内存的属性!!!

基本原理

共享内存:通过让不同的进程,看到通过一个内存块的方式就叫共享内存;

我们把创建好的内存称为共享内存;进程和共享内存建立映射关系称为挂接;取消进程和共享内存的映射关系称为释放内存空间;

创建共享内存

这里我们用的是shmget来创建共享内存;

size:要创建的共享内存的大小;

shmflg:标识符,IPC_CREAT ,IPC_EXCL;

  1. IPC_CREAT:如果创建的shm不存在,则创建;反之,则获取该内存并返回(总能获取一个shm);
  2. IPC_EXCL:单独使用没有意义;
  3. IPC_CREAT | IPC_EXCL:如果创建的shm不存在,则创建;反之,则出错返回;(意味着shm是全新的);

key:用户形成(唯一性的);保证看到同一份共享内存,能进行唯一性标识。如何形成?ftok

  • pathname:路径
  • proj_id:标识符

创建共享内存要先创建出key,在创建内存:

cpp 复制代码
key_t key = ftok(_path.c_str(), _proj_id);
        if (key < 0)
        {
            perror("ftok");
        }
        return key;
cpp 复制代码
int Shmget(key_t key,int size, int flag)
    {
        int shmid = shmget(key, size, flag);
        if (shmid < 0)
        {
            perror("shmget");
        }
        return shmid;
    }

共享内存创建好后,我们可以查询共享内存,验证一下是否创建成功;

查询共享内存:ipcs -m

删除共享内存

删除共享内存:ipcrm -m +shmid

shmid:创建共享内存的返回值;

cmd:通常为IPC_RMID;

buf:用于存储共享内存的信息;

key VS shmid

  • key:用户形成,内核使用的一个字段,用户不能使用key来进行shm的管理,内核进行区分shm的唯一性的(类比于struct file来理解);
  • shmid:内核给用户返回的一个标识符,用来进行用户级对共享内存进行管理的id值(类比于fd来理解);

共享内存的挂接

  • shmat:关联共享内存
  • shmdt:去关联

shmaddr:指定虚拟地址,但是我们并不了解,直接设置为nullptr即可;shmflg:读取权限,默认为0

cpp 复制代码
    void *Attachshm()
    {
        void * shmaddr=shmat(_shmid,nullptr,0);
        if(shmaddr==nullptr)
        {
            perror("shmat");
        }
        cout<<"who: "<<_who<<"   attach shm..."<<endl;
        return shmaddr;
    }
cpp 复制代码
void deleteshm(void * shmaddr)
    {
        if(shmaddr==nullptr)return ;
        int res = shmdt(shmaddr); 
    }

这样我们就完成的通信前的准备工作;

实现通信

我们把准备工作完成后,通信过程就比较简单了;因为共享内存是一段内存,我们在访问一个内存时,如果权限够的话,可以直接进行读取和写入;

不管我们运行代码时会发现一个问题就是我们的内容还没有写完,就会被读取;这是因为共享内存不提供对共享内存的任何保护机制 ----->数据不一致问题;

怎么解决这个问题???

我们只需要引入管道即可解决;

共享内存是所有进程间通信速度是最快的,因为共享内存是被双方所共享,只要写入对方就能立即看到,能大大减少数据的拷贝次数。

消息队列(了解)

消息队列概念

消息队列是OS 提供的内核级队列,消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法,每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

消息队列接口

  • msgget:获取消息队列
  • msgctl:控制消息队列
  • msgsnd:发送消息
  • msgrcv:读取消息

操作指令

ipcs -q

ipcrm -q +msgid

信号量(了解)

信号量概念

理解信号量

信号量、信号灯 ------->保护临界资源(code)

类比于去电影院看电影,人们必须要买票才能进去看电影;

  • 电影院:共享资源(临界资源);
  • 买票:申请信号量;
  • 票数:信号量的初始值;

申请信号量本质 就是对公共资源的预定机制;

信号量的本质是一个计数器,通常用来表示公共资源中,资源数的多少问题。信号量主要用于同步和互斥的。

既然信号量本质是一个计数器,那么可以用一个全局变量来代替吗?

不行,全局变量不能让所有进程都能看到,而且count++/count--不是原子的;

信号量操作

  • semget:申请信号量
  1. nsems:申请信号量的个数
  2. semflg:IPC_CREAT ,IPC_EXCL;
  • semctl:删除信号量
  1. semid:semget的返回值;
  • semop:信号量操作
相关推荐
JEECG低代码平台几秒前
不买服务器也能异地组网:开源 P2WLAN 把两地电脑“插“进同一台路由器
运维·服务器·开源·开源软件
欣欣之王来了6 分钟前
前端开发学习路线图:2026年Vue方向最新版
前端·学习·架构·项目·vue3教程
wdfk_prog10 分钟前
LWIP教程 00:从网线上的电信号到 lwIP——PHY、MAC、DMA 与 `netif` 的完整边界
运维·网络·笔记·学习·ip
cehuishi952717 分钟前
测绘外业调查如何正确的开展
运维·服务器·网络
lisanmengmeng25 分钟前
NRPE 添加命令(三)
java·linux·服务器
zmsup36 分钟前
从运维需求到产品能力:OpsArk Agent 的运维智能平台架构设计思路
运维·系统架构·agent·智能体·运维智能平台
人工智能培训40 分钟前
数字孪生驱动大模型工业知识库:为具身机器人植入领域专业经验
大数据·linux·服务器·前端·人工智能
m0_734172421 小时前
Python用zip配对前先检查长度
python·学习
乌暮1 小时前
拆解网页的底层逻辑:用费曼学习法讲透 HTML 与 CSS
前端·css·学习·html
江屿风1 小时前
【Linux系统】【从菜鸟驿站到操作系统:一节课打通Linux重定向与缓冲区真相】流食般投喂
linux·运维·服务器·开发语言·笔记