【共享内存】

news2024/11/24 2:01:56

1 共享内存示意图

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

 


2 共享内存数据结构

struct shmid_ds {
 struct ipc_perm shm_perm; /* operation perms */
 int shm_segsz; /* size of segment (bytes) */
 __kernel_time_t shm_atime; /* last attach time */
 __kernel_time_t shm_dtime; /* last detach time */
 __kernel_time_t shm_ctime; /* last change time */
 __kernel_ipc_pid_t shm_cpid; /* pid of creator */
 __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
 unsigned short shm_nattch; /* no. of current attaches */
 unsigned short shm_unused; /* compatibility */
 void *shm_unused2; /* ditto - used by DIPC */
 void *shm_unused3; /* unused */
};

3 共享内存函数(重点)

  • shmget函数:
功能:用来创建共享内存
原型 :
int shmget(key_t key, size_t size, int shmflg);
参数 :
key: 这个共享内存段名字 ;
size: 共享内存大小 ;
shmflg: 由九个权限标志构成,它们的用法和创建文件时使用的 mode 模式标志是一样的 ;
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回 -1。

 shmflg一般常用的权限位有两个:IPC_CREAT and IPC_EXCL

  • 单独使用IPC_CREAT: 创建一个共享内存,如果共享内存不存在,就创建之,如果已经存在,获取已经存在的共享内存并返回;
  • IPC_EXCL不能单独使用,一般都要配合IPC_CREAT;
  • IPC_CREAT | IPC_EXCL: 创建一个共享内存,如果共享内存不存在,就创建之, 如果已经存在,则立马出错返回 -- 如果创建成功,对应的shm,一定是最新的.

 我们如何获得该函数的第一个参数key呢?

我们可以使用ftok函数:

用返回值接受到生成的key_t类型即可。

  • shmat函数:
功能:将共享内存段连接到进程地址空间
原型 :
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数 :
shmid: 共享内存标识
shmaddr: 指定连接的地址 ,不指定就设置位空;
shmflg: 它的两个可能取值是 SHM_RND SHM_RDONLY ,也可以设置为0;
返回值:成功返回一个指针,指向共享内存第一个节;失败返回 -1
说明:
shmaddr NULL ,核心自动选择一个地址
shmaddr 不为 NULL shmflg SHM_RND 标记,则以 shmaddr 为连接地址。
shmaddr 不为 NULL shmflg 设置了 SHM_RND 标记,则连接的地址会自动向下调整为 SHMLBA 的整数倍。公式: shmaddr -
(shmaddr % SHMLBA)
shmflg=SHM_RDONLY ,表示连接操作用来只读共享内存。
  • shmdt函数 :
功能:将共享内存段与当前进程脱离
原型 :
int shmdt(const void *shmaddr);
参数 :
shmaddr: shmat 所返回的指针 ;
返回值:成功返回 0 ;失败返回 -1 ;
注意:将共享内存段与当前进程脱离不等于删除共享内存段。
  •  shmctl函数:
功能:用于控制共享内存
原型 :
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数 :
shmid: shmget 返回的共享内存标识码
cmd: 将要采取的动作(有三个可取值)
buf: 指向一个保存着共享内存的模式状态和访问权限的数据结构 ;
返回值:成功返回 0 ;失败返回 -1。

 


4 用共享内存实现一个客户端与服务端通信的案例

comm.hpp:

#include<iostream>
#include<cerrno>
#include<cstring>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/stat.h>
#include<unistd.h>
using namespace std;

#define PATHNAME "."
#define PROJID 6666
key_t getKey()
{
    key_t key=ftok(PATHNAME,PROJID);
    if(key==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }
    return key;
}

int creatShm(size_t size,int shmflag=0)
{
    umask(0);
    int shmid=shmget(getKey(),size,IPC_CREAT | IPC_EXCL | 0666);
    if(shmid==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }
    return shmid;
}


int getShm(size_t size,int shmflag=0)
{
    int shmid=shmget(getKey(),size,IPC_CREAT );
    if(shmid==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return 1;
    }
    return shmid;
}


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

void detouchShm(char* start)
{
    int n=shmdt(start);
    if(n==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return ;
    }
}

void delShm(int shmid)
{
    int n=shmctl(shmid,IPC_RMID,nullptr);
    if(n==-1)
    {
        cout<<"error"<<errno<<":"<<strerror(errno)<<endl;
        return ;
    }
}

server.cc:

#include<iostream>
#include"comm.hpp"


int main()
{
    //1 创建共享内存
    int shmid=creatShm(4096);

    //2 将共享内存与自己关联起来
    char* start=attachShm(shmid);

    //3 使用共享内存通信
    int cnt=0;
    while(cnt<=15)
    {
        cout<<start<<endl;
        sleep(1);
        ++cnt;
    }

    //4 解除自己与共享内存的关联
    detouchShm(start);

    //5 删除共享内存
    delShm(shmid);
    return 0;
}

client.cc:

#include<iostream>
#include"comm.hpp"


int main()
{
    //1 创建共享内存
    int shmid=getShm(4096);

    //2 将共享内存与自己关联起来
    char* start=attachShm(shmid);

    //3 使用共享内存通信
    char ch='A';
    while(ch<='Z')
    {
        start[ch-'A']=ch;
        ++ch;
        start[ch-'A']=0;
        sleep(1);
    }    
    //4 解除自己与共享内存的关联
    detouchShm(start);

    //客户端不要删掉共享内存
    return 0;
}

这样我们便能够正常运行我们的程序了,但是假如我们不小心终止了./server进程而导致共享内存没有被删除,我们可以用命令行来删除共享内存。

查看共享内存命令:

ipcs -m

删除指定共享内存:

ipcrm -m 共享内存的id

共享内存是没有互斥同步机制的,也就是说你在写数据的时候我能够直接读取数据,这个跟管道有很大区别,管道是你写完了后我再来读取数据,管道是需要互斥同步机制的,这个我们放到后面多线程再来补充。

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

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

相关文章

Mysql 学习(十 三)InnoDB的BufferPool

为什么要有缓存&#xff1f; 我们知道每次获取数据我们都需要从磁盘获取&#xff0c;磁盘的运行速度又慢的不行&#xff0c;对于这一个问题我们要怎么解决呢&#xff1f;我们把查询结果存储起来不就行了&#xff0c;因为当需要访问某个页的数据时&#xff0c;就会把完整的页的…

再见SpringSecurity,比Shiro更简单优雅的轻量级Sa-Token框架我粉了

1. 技术选型 最近在做登录、授权的功能&#xff0c;一开始考虑到的是spring boot spring security&#xff0c;但spring security太重&#xff0c;而我们是轻量级的项目&#xff0c;所以&#xff0c;spring security不适合我们。 而后考虑spring boot shiro&#xff0c;但s…

SSD202 Linux开发日志记录

一、挂载U盘 SDK默认自动加载USB存储模块&#xff0c;但没有自动挂载&#xff0c;插上U盘后识别sda mount /dev/sda /mnt/即可在/mnt查看U盘文件 二、make & make menuconfig提示失败 打开新终端后输入 declare -x ARCH"arm" declare -x CROSS_COMPILE"…

记一次php 导出word文档

导出试卷 先看效果 $paper Exam::where(id, $data[examid])->field(paper_id,title)->find();$bankIds PaperStorehouse::where(id, $paper[paper_id])->value(banks);$field type,rate,name,options,parsing,value,question_id,parsing_id;$bankInfo Banks::whe…

北邮22信通:二叉树显示路径的两种方法 递归函数保存现场返回现场的实例

北邮22信通一枚~ 跟随课程进度每周更新数据结构与算法的代码和文章 持续关注作者 解锁更多邮苑信通专属代码~ 获取更多文章 请访问专栏~ 北邮22信通_青山如墨雨如画的博客-CSDN博客 一.讲解 要想实现二叉树的路径显示&#xff0c;我们要按照…

gitbook在centos上安装

1&#xff09;官网下载Node.js的Linux64位的二进制包:Download | Node.js 或者在线下载&#xff1a; wget https://nodejs.org/dist/v12.16.1/node-v12.16.1-linux-x64.tar.xz ​​2)到指定目录​解压 cd /opt/gitbook tar -xJf node-v12.16.1-linux-x64.tar.xz mv node-…

记录--按钮级别权限怎么控制

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 最近的面试中有一个面试官问我按钮级别的权限怎么控制&#xff0c;我说直接v-if啊&#xff0c;他说不够好&#xff0c;我说我们项目中按钮级别的权限控制情况不多&#xff0c;所以v-if就够了&#xff…

wifiWG233移植

驱动的移植 交叉编译WIFI原厂固件驱动 根据网上资料&#xff0c;和官方文档编译成功。 修改Makefile 修改交叉编译环境 执行 make 编译成功&#xff0c;生成88x2bu.ko 加载原厂驱动 Insmod 88x2bu.ko 生成wlan0 Hostapd工具移植生成可连接热点AP 安装libnl库 使用命令tar …

ApiKit 接口调用、自动化测试工具

作为一位后端开发&#xff0c;我们平时经常需要维护API文档、对API接口进行调试、有时候还得Mock数据。Postman虽然作为接口调试工具非常好用&#xff0c;但是对于维护API文档这类工作却不太合适。今天给大家推荐一款功能更强大的工具ApiKit&#xff0c;足以满足我们对API的各种…

如何清除电脑缓存?分享3个有效的方法!

案例&#xff1a;我发现我的电脑运行速度越来越慢&#xff0c;影响使用体验。朋友说可能是我没有及时清理电脑缓存文件所致&#xff0c;那如何清理缓存的文件&#xff1f; 【我想通过清理电脑缓存文件的方法&#xff0c;提高我电脑运行的速度&#xff0c;但是我不知道具体的操…

如何利用Citespace和vosviewer既快又好地写出高质量的论文及快速锁定热点和重点文献进行可视化分析?

基于Citespace和vosviewer文献计量学可视化SCI论文高效写作方法 CiteSpace是什么&#xff1f; 简单来说&#xff0c;它一款通过将国内外文献进行可视化分析来帮助你了解一门学科前世今生的软件。 面对成千上万篇的文献&#xff0c;怎样才能快速锁定自己最感兴趣的主题及科学…

取代 Docker Desktop?Podman Desktop 发布 GA 版本 1.0

Podman&#xff08;POD MANager&#xff09;是一个跨平台的容器管理工具&#xff0c;可用于管理容器、镜像、卷以及以容器组形式存在的 Pod。Podman 可以在 Linux 上直接运行容器&#xff0c;但在像 macOS 和 Windows 这样的平台&#xff0c;是通过虚拟机间接运行容器。 Podma…

「实在RPA·电商数字员工」契合电商数智转型需求

一、为什么说电商数智化转型很重要&#xff1f; 如今&#xff0c;电商发展速度惊人&#xff0c;并且已经取代了实体店购物的时代。在众多新型的消费方式下&#xff0c;各式的电商行业如何运作&#xff0c;并且在短时间内完成各项任务&#xff0c;提升人们的生活质量。人们生活…

django admin后台列表页、修改/详情页图片预览功能

目录 一、admin后台列表页的图片预览功能 二、admin后台修改/详情页图片预览功能 1&#xff0c;添加html前端代码 2、在admin.py文件中添加以下代码&#xff1a; 1.列表页图片问题&#xff1a;在admin列表页中&#xff0c;直接在list_display中填写图片字段时在列表页展示的…

YOLOv5从训练到移植

一、图像采集和标注 图像采集 覆盖所有的数据目标&#xff0c;不同场景&#xff08;视角、光照、可能的干扰&#xff09;、距离、运动、背景等&#xff0c;用深度和广度摄像头都行。 若兼顾效率和准确率&#xff0c;可以用迁移学习思路训练&#xff0c;则不同场景下采集的图…

系统方面对文件的打开,读写,关闭

系统方面对文件的操作 1. 系统方面打开文件的函数2. 系统方面对文件的写入3. 系统方面对文件的读取4. 关闭文件close 1. 系统方面打开文件的函数 open函数得到一个指定文件的文件描述符&#xff0c;如果出现错误则返回-1。open函数需要传入一个文件路径和操作模式&#xff0c;…

高德地图AMap.MouseTool插件多次测距不能清除bug

AMap.MouseTool插件是一个很有用的插件&#xff0c;可以在地图上画折线测量距离&#xff0c;也可以在地图上画区域测量面积&#xff0c;这些在客户的一些高级需求里经常出现&#xff0c;最近使用出现了bug&#xff0c;此bug在官网的示例里也能重现 官网demo上重现步骤如下图&a…

剑指 Offer 58 - I. 翻转单词顺序

剑指 Offer 58 - I. 翻转单词顺序 题目&#xff1a; 输入一个英文句子&#xff0c;翻转句子中单词的顺序&#xff0c;但单词内字符的顺序不变。为简单起见&#xff0c;标点符号和普通字母一样处理。例如输入字符串"I am a student. “&#xff0c;则输出"student. a …

Spring Tool Suite(STS)初始化配置记录

目录 1.前言 2.STS安装 3.STS配置 3.1.SpringToolSuite4.ini 3.2、配置maven 3.3.配置jdk 3.4.全局编码设置 3.5.字体配置 3.6.设置自动提示 4. Spring插件 4.1.MyBatipse--mybatis插件 4.2.Spark Builder Generator 4.3.Properties Editor 4.4.Checkstyle 4.5.…

【MySQL】数据库的基本操作

&#x1f3e0; 大家好&#xff0c;我是 兔7 &#xff0c;一位努力学习C的博主~&#x1f4ac; &#x1f351; 如果文章知识点有错误的地方&#xff0c;请指正&#xff01;和大家一起学习&#xff0c;一起进步&#x1f440; &#x1f680; 如有不懂&#xff0c;可以随时向我提问&…