Linux学习笔记:进程间的通信.共享内存shm

共享内存shm

  • 什么是共享内存shm
  • 共享内存的特点
  • 关键函数
    • ftok
    • shmget
    • shmat
    • shmdt
    • shmctl
  • 代码示例

什么是共享内存shm

进程间通信的前提:必须让不同的进程看到同一份资源,并且这个资源是OS提供的

而共享内存(Share memory)就是在内核共享内存区找一块物理内存空间,并允许多个进程共享同一块内存区域的机制

不同于消息队列或管道,共享内存允许进程直接读写共享区域,因此具有较高的性能。通常情况下,共享内存用于需要频繁交换数据的场景,例如图形处理、数据库管理等。

原理图:
在这里插入图片描述
图片来源于bing搜索

共享内存的特点

  • 共享内存的通信方式,不会提供同步机制,共享内存是直接裸露给所有使用者的,因此在使用共享内存的时候一定要注意安全问题
  • 共享内存是所有进程通信中速度最快的,因为进程间的这块内存是共享的,因此这块内存中的数据是不需要进行拷贝等操作,每个进程可以直接访问
  • 共享内存一般是可以提供较大的空间的

关键函数

ftok

ftok函数可以理解为file to key ,在linux下,一切皆文件,因此共享内存也可以被看成是文件,这里的file就指的是共享的那块物理内存,而ftok 函数用于生成一个与给定路径名和项目标识符相关联的键值(key),用于后续共享内存的创建或连接。
在这里插入图片描述
通常在创建共享内存之前,需要使用 ftok 函数生成一个键值,以确保不同进程能够访问同一块共享内存。

shmget

shmget 函数用于创建共享内存段或获取现有共享内存段的标识符。shmget 函数接受三个参数:键值(key)、大小(size)和标志(flags)。键值通常由 ftok 函数生成,大小是要创建的共享内存段的大小一般为4096的整数倍,标志用于指定创建共享内存段的权限和行为。
在这里插入图片描述
标志位flags一般会用到两个参数 IPC_CREATE 和 IPC_EXCL,一般情况下 IPC_EXCL不单独使用 IPC_CREATE是创建否则获取.

通过 shmget 函数可以创建新的共享内存段,或者获取已经存在的共享内存段的标识符。

shmat

shmat 函数用于将共享内存段连接到调用进程的地址空间,从而可以访问共享内存中的数据。
在这里插入图片描述
shmat 函数接受三个参数:共享内存标识符(shmid)、地址(shmaddr)和标志(flags)。共享内存标识符是由 shmget 函数返回的共享内存段标识符,地址是要将共享内存映射到的地址,如果为 NULL,则由系统自动选择,标志用于指定连接共享内存的行为。
最终返回一个指向共享内存的指针,用于后续对共享内存的访问。
通过 shmat 函数将共享内存连接到进程的地址空间,使得进程可以直接访问共享内存中的数据。

shmdt

shmdt 函数用于从调用进程的地址空间分离共享内存段,停止对共享内存的访问。
在这里插入图片描述
shmdt 函数接受一个参数,即指向共享内存的指针。
通过 shmdt 函数可以停止对共享内存的访问,并释放与之相关的资源。

shmctl

shmctl 函数用于对共享内存进行控制操作,如获取信息、设置权限、删除共享内存等。
在这里插入图片描述
shmctl 函数接受三个参数:共享内存标识符(shmid)、命令(cmd)和缓冲区(buf)。共享内存标识符是由 shmget 函数返回的共享内存段标识符,命令用于指定要执行的控制操作,缓冲区用于存放返回的信息或接收需要设置的参数。
通过 shmctl 函数可以对共享内存进行各种控制操作,如获取信息、设置权限、删除共享内存等。

代码示例

在下面的代码示例中,我创建了两个.cc文件 server.cc 和 client.cc ,在这两个cpp文件身生成的进程中有一段共享内存来传递信息,并插入命名管道使之具有更明显的分工效果

server.cc

#include<iostream>
#include<sys/ipc.h> //Inter-Process Communication
#include<sys/shm.h>
#include<cstring>


#include"comm.hpp"
 
int main()
{   
    //创建管道
    bool r = Makefifo();
    if(!r) return 1;

      //创建唯一的k用于两进程找到这段共享内存的标识 调用函数 ftok
    key_t k = GetKey();
  
    // 创建共享内存   
    int shmid = CreatShm(k);

    //挂载共享内存
    std::cout<<"开始将shm映射到我的进程中"<<std::endl;
    char* s = (char*)shmat(shmid,nullptr,0); 

    //根据客户端输入内容来从共享内存中获取内容
    int fd = open(filename.c_str(),O_RDONLY);

    while(true)
    {
        int code = 0;
        ssize_t n = read(fd,&code,sizeof(code));
        if(n > 0)
        {
            std::cout<<"共享内存:"<< s << std::endl;
        }
        else if(n == 0)
        {
            break;
        }
    }


    //将shm从进程中移除
    shmdt(s);
    std::cout<<"将shm从进程中移除"<<std::endl;

    //删除shm
    shmctl(shmid,IPC_RMID,nullptr);
    std::cout<<"将shm从os中删除"<<std::endl;
    

    return 0;
}

client.cc

#include<iostream>
#include<sys/ipc.h> //Inter-Process Communication
#include<sys/shm.h>
#include<cstring>

#include"comm.hpp"
 
int main()
{   //获取k
    key_t k = GetKey();
    
    //获取shm
    int shmid = GetShm(k);

    //挂载共享内存到进程
    char* s = (char*)shmat(shmid,nullptr,0);

    //获取管道fd
    int wfd = open(filename.c_str(),O_WRONLY);

    //对共享内存和管道进行输入,若写入共享内存,在通知管道可读
    char c = 'a';
    for(;c <= 'z';c++)
    {
        s[c - 'a'] = c;
        int code = 1;
        write(wfd,&code,sizeof(code));
        std::cout<<"write " << c << " done" << std::endl;
        sleep(1);
    }

    //删除管道
    unlink(filename.c_str()); 
    
    //将shm从进程中移除
    shmdt(s);
    std::cout<<"将shm从进程中移除"<<std::endl; 

    //因文共享内存机制的原因,两个进程是不会因此而同步,对两个进程说就是一个公共空间,里面的内容谁想用就用,想改就可以个改

    


    return 0;
}

comm.hpp

#pragma once

#include<iostream>
#include<string>
#include<fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include<unistd.h>

const std::string pathname = "/home/cris/vscodef";
const int proj_id = 0x11223344;
const std::string filename = "fifo";

const int sh_size = 4096;  //共享内存的大小最好设置成4096的倍数

key_t GetKey()
{

    key_t k = ftok(pathname.c_str(),proj_id);
    if(k < 0)
    {
        std::cerr << "errno:" << errno << ",errstring" << strerror(errno) <<std::endl;
        exit(1);
    }
    std::cout<< "key:" << k << std::endl;

    return k;

}


int CreatShmHelper(key_t key , int flag)
{
     //共享内存的生命周期是随内核的   查看共享内存:ipcs -m  删除: ipcrm -m shmid
    // 调用函数shmget  此函数技能创建又能获取  
    //一般情况下 IPC_EXCL不单独使用  IPC_CREATE是创建否则获取
    /// int shmget(key_t key,size_t size ,int shmflg)
    int shmid = shmget(key,sh_size,flag);
    if(shmid < 0)
    {
        std::cerr << "errno:" << errno << ",errstring" << strerror(errno) <<std::endl;
        exit(2);
    }
    std::cout<< "shmid:" << shmid << std::endl;
    return shmid;
}

int CreatShm(key_t key)
{
    return CreatShmHelper(key,IPC_CREAT|IPC_EXCL|0644);
}

int GetShm(key_t key)
{
    return CreatShmHelper(key,IPC_CREAT);
}


bool Makefifo()
{
    int n = mkfifo(filename.c_str(),0666);
    if(n < 0)
    {
        std::cerr << "errno" << errno << ",errstring" << strerror(errno) << std::endl;
        return false;
    }
    return true;
}

Makefile

.PHONY:all
all:client server

client:client.cc
	g++ -o $@ $^ -std=c++11
server:server.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f server client fifo

运行效果如图:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

远距离、高品质、低延迟、高保真——SA316无线音频模块带您探索新的音频体验

SA316系列产品分为发射端模块SA316S-TX,SA316F30和接收端模块SA316-RX&#xff0c;该系列方案采用了无线高品质的语音传输芯片来设计&#xff0c;它可以支持外部 PCM / IIS 双模数字音频接口&#xff0c;同时模块为客户提供了标准化的串行接口&#xff0c;使用者可通过串口指令…

使用QT完成如图的游戏登录界面 使用信号和槽完成密文明文密码转换,重置账号和密码,登录校验 详细代码在主页下载

头文件: #ifndef LOGINWIDGET_H #define LOGINWIDGET_H #include <QLineEdit> #include <QPushButton> #include <QWidget> class LoginWidget : public QWidget {Q_OBJECT public: LoginWidget(QWidget *parent = 0); ~LoginWidget(); public slots: …

全新神经网络架构KAN一夜爆火!200参数顶30万,MIT华人一作 | 最新快讯

白交衡宇发自凹非寺 量子位公众号 QbitAI 一种全新的神经网络架构 KAN&#xff0c;诞生了&#xff01; 与传统的 MLP 架构截然不同&#xff0c;且能用更少的参数在数学、物理问题上取得更高精度。 比如&#xff0c;200 个参数的 KANs&#xff0c;就能复现 DeepMind 用 30 万参数…

SpringCloud整合Gateway结合Nacos

目录 一、引入依赖 二、开启两个测试项目 2.1 order service ​编辑 2.2 user service 三、gateway项目 3.1 新建一个bootstrap.yml文件 3.2 将我们的的网关配置写道nacos里的配置里 3.3 测试&#xff1a;看能够根据网关路由到两个测试的项目 四、 优化 4.1 将项目打包…

低空经济+飞行汽车:eVTOL技术详解

低空经济是以各种有人驾驶和无人驾驶航空器的各类低空飞行活动为牵引&#xff0c;辐射带动相关领域融合发展的综合性经济形态。它广泛体现于第一、第二、第三产业之中&#xff0c;在促进经济发展、加强社会保障、服务国防事业等方面发挥着日益重要的作用。 飞行汽车&#xff0c…

## CSDN创作活动:缓解工作压力:程序员的健康之道

缓解工作压力&#xff1a;程序员的健康之道 在当今快节奏的社会中&#xff0c;程序员作为一个高度专业化和技术密集的群体&#xff0c;往往需要面对持续的工作压力和创新挑战。在如此高强度的工作环境下&#xff0c;如何有效缓解工作压力&#xff0c;保持工作效率和个人健康成…

7个AI工具助力产品管理提升

大家好&#xff0c;人工智能AI技术不断进步&#xff0c;AI在产品管理领域的应用也日益广泛。AI以辅助者的角色助力提升产品优化流程的效率&#xff0c;同时激发创新&#xff0c;是不可或缺的强大伙伴。本文将介绍七个AI工具&#xff0c;旨在自动化产品管理者的日常工作流程&…

Unity SteamVR入门

概述 VR项目现在在当前已经是非常热门的技术&#xff0c;可以给玩家身临其境的感觉&#xff0c;接下来让我们学习这部分的内容吧&#xff01; SteamVR Input SteamVR绑定流程&#xff0c;在Windows窗口的点击SteamVR-input&#xff0c;图1&#xff0c;在这里可以选择你需要绑定…

探秘Redis分布式锁:实战与注意事项

【更多精彩内容,欢迎关注小米的微信公众号“软件求生”】 大家好!我是小米,一个热爱分享技术的29岁技术达人。今天,我们来聊聊一个很有意思的主题——Redis分区容错之分布式锁。在分布式系统中,锁是一个非常重要的概念,它能确保系统中资源的并发访问不会出现问题。Redis…

如何使用Go语言进行基准测试(benchmark)?

文章目录 一、基准测试的基本概念二、编写基准测试函数三、运行基准测试四、优化代码性能五、注意事项总结 在Go语言中&#xff0c;基准测试&#xff08;benchmark&#xff09;是一种评估代码性能的有效方式。通过基准测试&#xff0c;我们可以测量代码执行的时间、内存使用情况…

【CANoe示例分析】TCP Chat(CAPL) with TLS encription

1、工程路径 C:\Users\Public\Documents\Vector\CANoe\Sample Configurations 15.3.89\Ethernet\Simulation\TLSSimChat 在CANoe软件上也可以打开此工程:File|Help|Sample Configurations|Ethernet - Simulation of Ethernet ECUs|Basic AUTOSAR Adaptive(SOA) 2、示例目…

快速掌握Element-Ul,构建高效网页应用【AI写作】

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

并发编程之线程池的设计和原理

一、线程池 提前创建一系列的线程&#xff0c;保存在这个线程池中&#xff0c;有任务要执行的时候&#xff0c;从线程池中取出线程来执行。没有任务的时候&#xff0c;线程池放回去。 二、为什么要使用线程池 线程使用上的问题: 线程的频繁创建 和 销毁 线程的数量过多&…

注册表获取autoCAD安装位置

注意事项 注意&#xff1a;①64位操作系统注册表会重定向&#xff0c;RegOpenKeyEx第4个参数得加上KEY_WOW64_64KEY&#xff1b;②RegOpenKeyEx遍历子项时注意第2和第4参数&#xff0c;参考图&#xff1a; ③RegQueryValueEx同样得注意第6参数 完整代码 std::unordered_map…

Mybatis进阶(映射关系多对一 )

文章目录 1.需求分析2.应用实例&#xff08;xml配置&#xff09;1.数据表设计2.entity设计&#xff08;不要使用toString会栈溢出&#xff09;1.Pet.java2.User.java 3.编写Mapper1.PetMapper.java2.UserMapper.java 4.编写Mapper.xml1.UserMapper.xml2.PetMapper.xml 5.测试Us…

OPPO A72/A55/K7X/A53真我Q3S等手机ROOT刷机后广电卡没信号不读卡解决办法

目前运营商除了移动联通电信以外&#xff0c;还存在1个中国广电&#xff0c;广电属于第四大运营商&#xff0c;由于广电起步较晚&#xff0c;对于手机频段要求也自然不一样&#xff0c;导致目前市面上部分手机出厂没有信号或者不读卡等问题&#xff0c;特别在手机被用户自行刷机…

如何快速的追加文章的内容(在不知道内容的情况下)

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 1、打开工具&#xff0c;切换到文章模块下&#xff0c;快捷键&#xff1a;Ctrl1 2、新建一个文章做演示&#xff0c;001 3、添加一个内容&#xff0c;就随…

蚂蚁面试:Springcloud核心组件的底层原理,你知道多少?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团、蚂蚁、得物的面试资格&#xff0c;遇到很多很重要的相关面试题&#xff1a; 说说&#xff1a;蚂蚁面试&#xff1…

【Java】HOT100 贪心算法

目录 理论基础 一、简单贪心 LeetCode455&#xff1a;分发饼干 二、中等贪心 2.1 序列问题 LeetCode376&#xff1a;摆动序列 2.2 贪心股票问题 LeetCode121&#xff1a;买卖股票的最佳时机 LeetCode121&#xff1a;买卖股票的最佳时机ii 2.3 两个维度权衡问题 LeetCode135&…

【06016传感器原理与应用】第5章 气敏传感器 期末复习自考复习

第5章 气敏传感器 能够把气体信息变成电信号的装置。 一、学习目的与要求 通过本章的学习&#xff0c;熟悉并掌握气体传感器的工作原理和硬件组成结构。熟练掌握几种电阻式尤其TiO2、SnO2气敏传感器、非电阻式气敏传感器、固体电解质传感器、接触燃烧式气敏传感器的基本原理…