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

news2024/12/28 22:09:43

共享内存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

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

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

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

相关文章

西瓜书学习——决策树形状、熵和决策树的本质

文章目录 决策树形状监督学习算法分类与回归 熵信息熵香农熵 (Shannon Entropy) - H(X)联合熵 (Joint Entropy) - H(X, Y)条件熵 (Conditional Entropy) - H(Y|X)互信息 (Mutual Information) - I(X; Y)相对熵 (Relative Entropy) / KL散度 (Kullback-Leibler Divergence) - DK…

学习CSS3,实现红色心形loading特效

试想一下&#xff0c;如果你的网站在加载过程中&#xff0c;loading图由一个老旧的菊花转动图片&#xff0c;变为一个红色的心形loading特效&#xff0c;那该有多炫酷啊。 目录 实现思路 初始化HTML部分 延迟动画是重点 设定动画效果 完整源代码 最后 实现思路 每个…

怎样批量将jpg图片转换成HEIC格式?jpg快速转换成HEIC图片

heic格式和jpg格式图片大家都很熟悉了。那么这两种图片格式的区别是什么&#xff1f;哪种格式图片更好一些&#xff1f; 一&#xff0c;区别&#xff1a;jpg和HEIC的区别 1&#xff0c;jpg格式有良好的压缩性能和良好的重建质量而被广泛应用于图像和视频处理中。 2&#xff…

HarmonyOS实战开发-RPC连接、如何实现前台选择商品和数目,后台计算总价的功能

介绍 本示例使用ohos.rpc 相关接口&#xff0c;实现了一个前台选择商品和数目&#xff0c;后台计算总价的功能&#xff0c;使用rpc进行前台和后台的通信。 效果预览 使用说明&#xff1a; 点击商品种类的空白方框&#xff0c;弹出商品选择列表&#xff0c;选择点击对应的商品…

常用工具网站

代码生成器&#xff1a; SQL转Java代码生成器 | 不求人导航SQL转Java代码生成器https://codegen.bqrdh.com/

面试题-Redis篇

什么是 Redis? Redis 是完全开源免费的&#xff0c;遵守 BSD 协议&#xff0c;是一个高性能的 key-value 数据库。 Redis 与其他 key - value 缓存产品有以下三个特点&#xff1a; Redis 支持数据的持久化&#xff0c;可以将内存中的数据保存在磁盘中&#xff0c;重启的时 …

windows10 H2database 安装教程

1. 下载https://www.h2database.com/html/download.htmlhttps://www.h2database.com/html/download.html 具体版本可以根据项目配置的版本 2. 安装 3.手动启动 安装完后默认启动&#xff0c;如退出后需手动启动则在安装目录下启动。 启动完&#xff0c;在桌面右下角会出现小图…

春游江淮 请来池州 | 五一池州文旅活动时间表大集合,都在这里

快到五一,想好去哪里玩吗?来池州,各景区缤纷活动登场&#xff0c; 速速划重点、敲黑板! 五一放大招!到底怎么玩?文旅活动、阅读推广 非遗展示......现在都已经为你整理好啦!这份超齐全的 五一假期文旅活动时间表,助力您玩转各景区,整个假期嗨不停~ 旅游惠民活动 表演类活动…

一、初识Django

简介 Django 是一个用于构建 Web 应用程序的高级 Python Web 框架。 版本对应 不同版本的django框架是基于特定的不同的python版本开发的&#xff0c;所以不同版本的django框架要正常执行功能只能安装特定的python版本 Django安装 安装 Django # 全局安装 pip install dj…

Python | Leetcode Python题解之第50题Pow(x,n)

题目&#xff1a; 题解&#xff1a; class Solution:def myPow(self, x: float, n: int) -> float:def quickMul(N):ans 1.0# 贡献的初始值为 xx_contribute x# 在对 N 进行二进制拆分的同时计算答案while N > 0:if N % 2 1:# 如果 N 二进制表示的最低位为 1&#xf…

Java面试八股之简述Java中assert的作用

简述Java中assert的作用 Java中的assert关键字用于在代码中插入断言&#xff08;Assertion&#xff09;&#xff0c;断言是一种在开发和测试阶段用于验证程序内部状态或假设的机制。其主要作用包括&#xff1a; 条件检查&#xff1a; assert语句用于在特定代码点上检查一个布…

2024年【氧化工艺】最新解析及氧化工艺复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 氧化工艺最新解析是安全生产模拟考试一点通总题库中生成的一套氧化工艺复审模拟考试&#xff0c;安全生产模拟考试一点通上氧化工艺作业手机同步练习。2024年【氧化工艺】最新解析及氧化工艺复审模拟考试 1、【单选题…

小白也能看懂,手机短信恢复方法其实很简单!

手机短信是我们日常生活中不可或缺的一部分&#xff0c;有时候我们可能会不小心删除了一些重要的短信&#xff0c;有没有手机短信恢复方法呢&#xff1f;别担心&#xff0c;本文将为您介绍3个手机短信恢复的方法&#xff0c;让您轻松找回丢失的短信。 方法一&#xff1a;通过短…

80 行 JS 代码实现页面添加水印:文字水印、多行文字水印、图片水印、文字图片水印

80 行 JS 代码实现页面添加水印&#xff1a;文字水印、多行文字水印、图片水印、文字&图片水印 一、水印概括 1. 添加水印的好处 信息标识&#xff1a; 水印可以用于标识文档的所有者、保密级别、状态或其他相关信息&#xff0c;帮助用户更好地理解文档内容的属性版权保…

【基础算法】二分查找

1.二分查找 二分查找 思路&#xff1a; 朴素二分模版 class Solution { public:int search(vector<int>& nums, int target) {int l 0, r nums.size() - 1;while(l < r){int mid (l r) / 2;if(nums[mid] < target) l mid 1;else if(nums[mid] > ta…

Python中的类(Class)详解——新手指南

在Python编程中&#xff0c;类&#xff08;Class&#xff09;是一个非常重要的概念&#xff0c;它允许程序员创建自己的对象类型。这些对象类型可以包含数据&#xff08;称为属性&#xff09;和函数&#xff08;称为方法&#xff09;&#xff0c;它们定义了这些对象的行为。本文…

计算机毕业设计php自行车在线租赁管理系统-vue+mysql

本系统的开发使获取自行车在线租赁管理系统信息能够更加方便快捷&#xff0c;同时也使自行车在线租赁管理系统管理信息变的更加系统化、有序化。系统界面较友好&#xff0c;易于操作。 自行车在线租赁管理系统&#xff0c;主要的模块包括首页、个人中心、用户管理、会员管理、自…

Agent AI智能体:未来社会的无形引领者

目录 前言1. 智能体说明1.1 定义1.2 作用1.3 类型介绍1.4 核心技术 2. 技术进步与创新2.1 机器学习的进步2.2 深度学习与神经网络2.3 强化学习2.4 转移学习与多任务学习2.5 自然语言处理(NLP)的革新2.6 知识图谱与推理 3. 行业领域应用场景3.1 游戏行业3.2 医疗健康3.3 金融服务…

值得推荐的文档透明加密软件TOP3

文档透明加密软件是一种可以对文档进行加密处理&#xff0c;同时保持文档的可读性和可编辑性的软件。通常&#xff0c;这种软件会在用户对文档进行保存或传输时自动对文档进行加密&#xff0c;而在用户需要访问文档时则会解密文档&#xff0c;以便用户正常地查看和编辑文档内容…

MySQL怎么看死锁记录

这个结果分成三部分&#xff1a; (1) TRANSACTION&#xff0c;是第一个事务的信息&#xff1b; (2) TRANSACTION&#xff0c;是第二个事务的信息&#xff1b; (3)WE ROLL BACK TRANSACTION (1)&#xff0c;是最终的处理结果&#xff0c;表示回滚了第一个事务。 第一个事务的信…