当前位置: 首页 > ops >正文

linux 进程间通信_共享内存

目录

一、什么是共享内存?

二、共享内存的特点

优点

缺点

三、使用共享内存的基本函数

 1、创建共享内存shmget()

2、挂接共享内存shmat

3、脱离挂接shmdt

 4、共享内存控制shmctl

 5.查看和删除共享内存

comm.hpp

server.cc 

Client.cc 

Makefile


一、什么是共享内存?

共享内存(Shared Memory)是一种高效的‌进程间通信(IPC)机制‌,允许多个进程直接访问同一块物理内存区域,实现数据的快速交换。它是IPC中速度最快的方式,因为共享内存方式的通信没有中间过程,而管道、消息队列等方式则需要将数据通过中间机制进行转换。

 共享内存的原理如上图所示,主要分为两部(创内存、挂接)

1.进程在物理内存上开辟一块空间,这块空间称为共享内存。

2.不同进程将这块空间挂接到自己的进程地址空间中。

3.进程通过虚拟地址和页表的映射找到共享内存,然后对共享内存进行读写数据。

二、共享内存的特点

优点

  1. 高效性‌:共享内存是所有进程间通信方式中速度最快的,因为所有进程共享同一块内存,访问共享内存区域和访问进程独有的内存区域一样快,并不需要通过系统调用或者其它需要切入内核的过程来完成。
  2. 直接访问‌:避免了数据的各种不必要的复制,数据直接写到内存,不用若干次数据拷贝。
  3. 灵活性‌:不像匿名管道那样要求通信的进程有一定的父子关系。

缺点

  1. 缺乏同步机制‌:系统内核没有对访问共享内存进行同步,必须提供自己的同步措施。例如,在数据被写入之前不允许进程从共享内存中读取信息、不允许两个进程同时向同一个共享内存地址写入数据等。
  2. 生命周期‌:共享内存的生命周期随内核,即如果用户不使用系统调用释放它,直到操作系统关机之前它会一直存在。
  3. 管理复杂性‌:需要额外的同步机制(如信号量、互斥锁)保证数据一致性。

三、使用共享内存的基本函数

 1、创建共享内存shmget()

 int shmget(key_t key, size_t size, int shmflg);
参数key:这个共享内存段名字(和消息队列一样由ftok获取)size:共享内存⼤⼩(自己指定,一般为页的整数倍)shmflg:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的IPC_CREAT:创建新的共享内存IPC_CREAT|IPC_EXCL|0666:若创建的共享内存存在,报错IPC_NOWAIT:非阻塞0:如果是打开文件,写0
返回值:成功返回⼀个⾮负整数,即该共享内存段的标识码;失败返回-1

2、挂接共享内存shmat

void *shmat(int shmid, const void *shmaddr, int shmflg);
参数shmid: 共享内存标识shmaddr:指定连接的地址(一般默认为NULL,由系统自动分配内存)shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY(连接操作用于只读内存)
返回值:成功返回⼀个指针,指向共享内存第⼀个节;失败返回-1

3、脱离挂接shmdt

 int shmdt(const void *shmaddr);
参数shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

 4、共享内存控制shmctl

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数shmid:由shmget返回的共享内存标识码cmd:将要采取的动作(有三个可取值)buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1

 5.查看和删除共享内存

//查看
ipcs -m
//删除
ipcrm -m id(标识)

共享内存使用案例:

分为两个进程,客户端(Client)和服务端(server) 

前提介绍:

.hpp文件的作用与.h文件功能类似

.cc文件等于.cpp文件

comm.hpp

#include <iostream>
#include<stdio.h>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include<string.h>const std::string gpath = "/root/day5_24";
const int gid = 0x6666;
const int gshmsize = 4096;
const int gmode = 0600;
class ShareMemory
{
public:ShareMemory() : _shmid(-1), _ret(nullptr){}~ShareMemory(){}// 创建共享内存int CreateShm(){key_t key = ::ftok(gpath.c_str(), gid);if (key < 0){printf("ftok error\n");return 1;}_shmid = ::shmget(key, gshmsize, IPC_CREAT | IPC_EXCL | gmode);if (_shmid < 0){printf("shmget error\n");return 2;}return _shmid;}// 获得共享内存void GetShm(){key_t key = ::ftok(gpath.c_str(), gid);if (key < 0){printf("ftok error\n");}_shmid = ::shmget(key, gshmsize, IPC_CREAT|gmode);std::cout << "_shmid: " << _shmid << std::endl;if (_shmid < 0){printf("shmget error\n");}}// 挂地址void AttachShm(){_ret = shmat(_shmid, nullptr, 0);std::cout <<  "_shmid: " << _shmid << std::endl;}// 去关联void DetachShm(){int d = shmdt(_ret);if (d == -1){printf("shmdt error\n");return;}printf("shmdt success\n");}// 释放内存void DeleteShm(){shmctl(_shmid, IPC_RMID, nullptr);}void *getadder(){return _ret;}void ShmMeta(){//}private:int _shmid;void *_ret;
};ShareMemory sm;

server.cc 

#include"time.hpp"
#include "Comm.hpp"
using namespace std;int main()
{sm.CreateShm();sm.AttachShm();// 在此处读出while(true){char* image=(char*)sm.getadder();std::cout << image << std::endl;sleep(1);}sm.DetachShm();sm.DeleteShm();return 0;
}

Client.cc 

#include "Comm.hpp"
#include"time.hpp"
int main()
{sm.GetShm();sm.AttachShm();// 在此处写入char*image = (char*)sm.getadder();char i[] = "i am processA";while (true){strcpy(image, i);sleep(1);}sm.DetachShm();return 0;
}

Makefile

SERVER=server
CLIENT=client
CC=g++
SERVER_SRC=Server.cc
Client_SRC=Client.cc.PHONY:all
all:$(SERVER) $(CLIENT)$(SERVER):$(SERVER_SRC)$(CC) -o $@ $^ -std=c++11 -g
$(CLIENT):$(Client_SRC)$(CC) -o $@ $^ -std=c++11 -g.PHONY:clean
clean:rm -f $(SERVER) $(CLIENT)

----------------------------------------------------------------------------------------------------------------------------

本篇介绍到此结束,有问题欢迎给我评论留言。谢谢

http://www.xdnf.cn/news/9039.html

相关文章:

  • Python打卡第37天
  • 数据结构基础知识补充
  • leetcode刷题日记——求根节点到叶节点数字之和
  • Python数据分析基础(一)
  • vue3自定义指令来实现 v-lazyImg 功能
  • IP地址查询的重要性
  • 01 NLP的发展历程和挑战
  • 第2章 程序设计语言基础知识
  • C#编解码:Base64扩展类的实现与应用
  • 人工智能如何协助老师做课题
  • 电子电路:什么是感应电动势?
  • C++ 模板函数深度指南
  • 【CF】Day66——Edu 168.D + CF 853 (Div. 2).C (树 + 二分 + 贪心 | 组合数学)
  • 佰力博科技与您探讨铁电分析仪具有哪些测试功能
  • [PyMySQL]
  • reflect-metadata作用
  • Ubuntu | NVIDIA 驱动、CUDA 与 cuDNN 的安装与配置 / 常见问题及解决方法
  • Zabbix集成Grfana自定义仪表盘
  • World of Warcraft [CLASSIC] Jewelcrafting Gemstone 3 [80 WLK]
  • 初等数论--Garner‘s 算法
  • 邻近标记技术(PL):探索生物分子相互作用的前沿工具
  • Java设计模式之适配器模式
  • AI时代新词-多模态(Multimodal)
  • 测评机构如何通过漏扫保障软件安全?扫描范围与局限解析
  • leetcode:2235. 两整数相加(python3解法,数学相关算法题)
  • 十六进制字符转十进制算法
  • C++——STL——unordered_map与unordered_set的使用以及使用哈希表封装unordered_map/set
  • https的进化之路(八卦版)
  • JVM 深度解析
  • k-way Hypergraph Partitioning via n-Level Recursive Bisection【2016 ALENEX】文献总结