[C++学习] 多进程通信共享内存

ref:https://blog.csdn.net/qq_35733751/article/details/82872197
多线程共享进程的地址空间,如果多个线程需要访问同一块内存,用全局变量即可。
在多进程中,每个进程的地址空间是独立的,不共享的,如果多个进程需要访问同一块内存,不能用全局变量,只能用共享内存。
共享内存Shared Memory 允许多个进程(不要求进程之间有血缘关系)访问同一块内存空间,是多个进程之间共享和传递数据最高效的方式。进程可以将共享内存连接到他们自己的地址空间,如果某个进程修改了共享内存中的数据,其他的进程读到的数据也会改变。
共享内存没有提供锁机制,也就是说,在某一个进程对共享内存进行读/写的时候,不会阻止其它进程对它的读/写。如果要对共享内存的读/写加锁,可以使用信号量。

Linux 操作共享内存需要四步:

  1. 调用shmget函数获取或创建共享内存
  2. 调用shmat函数把共享内存连接到当前进程的地址空间
  3. 调用shmdt函数把共享内存从当前进程中分离 shmdt是用来取消进程空间的地址空间和共享内存的物理地址的挂接,不让进程访问共享内存了。
  4. 调用shmctl函数删除共享内存
    通常不需要第4个,除非整个服务停止了。
    查看当前的共享内存命令
ipcs -m 
(base) ubuntu@ubuntu:~$ ipcs -m ------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 360454     ubuntu     600        1048576    2          dest         
0x00000000 229384     ubuntu     700        131072     2          dest         
0x00000000 229385     ubuntu     700        1290240    2          dest         
0x00000000 360459     ubuntu     600        524288     2          dest         
0x00000000 229389     ubuntu     600        524288     2          dest         
0x00000000 229393     ubuntu     600        4194304    2          dest         
0x00000000 327698     ubuntu     700        8192       2          dest         
0x00000000 21         ubuntu     600        57024      2          dest         
0x00000000 24         ubuntu     600        524288     2          dest         
0x00000000 29         ubuntu     600        4194304    2          dest         
0x00000000 327713     ubuntu     700        2101248    2          dest         
0x00000000 36         ubuntu     777        3110400    2          dest         
0x00000000 37         ubuntu     777        3110400    2          dest         
0x00000000 196647     ubuntu     700        16384      2          dest         
0x00000000 40         ubuntu     600        806400     2          dest         
0x00000000 41         ubuntu     600        7904376    2          dest         
0x00000000 196650     ubuntu     700        20480      2          dest         
0x5106002b 44         ubuntu     600        1          1                       
0x00000000 45         ubuntu     600        986168     2          dest         
0x00000000 47         ubuntu     600        7574616    2          dest         
0x00000000 48         ubuntu     600        914292     2          dest         
0x00000000 196663     ubuntu     700        2242800    2          dest         
0x00000000 196669     ubuntu     700        1474560    2          dest         

参数解析:
key 是 共享内存的标识符, 16进制,owner 创建共享内存的用户或进程的用户ID。perms 权限 bytes 内存的大小 nattch 链接进来的进程数量 status 状态
第七列是共享内存的状态status。其中显示“dest”表示共享内存段已经被删除,但是还有用户在使用它,当该段内存的mode字段设置为 SHM_DEST时就会显示“dest”。当用户调用shmctl的IPC_RMID时,内存先查看多少个进程与这个内存关联着,如果关联数为0,就会销 毁这段共享内存,否者设置这段内存的mod的mode位为SHM_DEST,如果所有进程都不用则删除这段共享内存。

ipcrm -m shmid 删除共享内存

以上列出的是使用默认的"ipcs -m"命令输出的列。
在这里插入图片描述

//
// Created by ubuntu on 9/7/23.
//
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>struct st_pid {int pid; // 进程编号char names[51]; // 进程名称
};int main(int argc, char *argv[]) {int key = 0x1234;int shmid;// 调用shmget函数获取或创建共享内存if ((shmid = shmget(key, sizeof(struct st_pid), 0640 | IPC_CREAT)) == -1) {printf("shmget(Ox1234) failed \n");return -1;}struct st_pid *stpid = 0;// 调用shmat函数把共享内存连接到当前进程的地址空间,On success, shmat() returns the address of the attached shared memory segmentif((stpid = (struct st_pid *)shmat(shmid, stpid, 0)) == (void *) -1) {printf("shmat failed\n");return -1;}//把共享内存从当前进程中分离//shmdt(stpid);}

要注意的是这一部分:

struct st_pid *)shmat(shmid, stpid, 0))

man 啥看shmat, 它返回的是void × 类型,所以要强制转换何曾 struct st_pid * , 因为是要用st_pid * 做的数据接收。
同时手册明确说了,错误后是返回值是 void× 类型的 -1

SYNOPSIS#include <sys/types.h>#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);RETURN VALUEOn success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, anderrno is set to indicate the cause of the error.On success, shmdt() returns 0; on error -1 is returned, and errno is set to indicate the cause of the error.

第三个参数:int shmflg 暂时用不到,需要传0;
shmflg参数:是一个权限标志位,如果shmflg = 0表示默认权限可读写,如果指定shmflg = HM_RDONLY表示只读模式,其他为读写模式。

参数shmaddr:表示进程空间的虚拟地址,shmat函数会把shmaddr地址映射到共享内存,具体如何映射是由参数shmaddr和shmflg来决定。
ref:ttps://blog.csdn.net/qq_35733751/article/details/82872197

删除共享内存:

函数原型:
shmctl(shmid, IPC_RMID, 0)
IPC_RMID表示没有进程绑定的时候才删除,第三个参数是啥意思???IPC_RMID  Mark  the  segment to be destroyed.  The segment will actually be destroyed only after the last process de‐taches it (i.e., when the shm_nattch member of the associated structure shmid_ds is zero).  The caller mustbe the owner or creator of the segment, or be privileged.  The buf argument is ignored.If  a  segment  has  been marked for destruction, then the (nonstandard) SHM_DEST flag of the shm_perm.modefield in the associated data structure retrieved by IPC_STAT will be set.The caller must ensure that a segment is eventually destroyed; otherwise its pages  that  were  faulted  inwill remain in memory or swap.See also the description of /proc/sys/kernel/shm_rmid_forced in proc(5).
(base) ubuntu@ubuntu:~/muke01/01sharemem$ ipcs -m  | grep 1234
0x00001234 1015831    ubuntu     640        56         1   

attach 是1了,代表有一个process attach了共享内存的地址。

//
// Created by ubuntu on 9/7/23.
//
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <string.h>struct st_pid {int pid; // 进程编号char names[51]; // 进程名称
};int main(int argc, char *argv[]) {int key = 0x1234;int shmid;// 调用shmget函数获取或创建共享内存if ((shmid = shmget(key, sizeof(struct st_pid), 0640 | IPC_CREAT)) == -1) {printf("shmget(Ox1234) failed \n");return -1;}struct st_pid *stpid = 0;// 调用shmat函数把共享内存连接到当前进程的地址空间,On success, shmat() returns the address of the attached shared memory segmentif ((stpid = (struct st_pid *) shmat(shmid, stpid, 0)) == (void *) -1) {printf("shmat failed\n");return -1;}printf("pid=%d,name=%s\n", stpid->pid, stpid->names);stpid->pid = getpid();strcpy(stpid->names, argv[1]);printf("pid=%d,name=%s\n", stpid->pid, stpid->names);sleep(10);//把共享内存从当前进程中分离shmdt(stpid);// 删除共享内存
//    if (shmctl(shmid, IPC_RMID, 0) == -1) {
//        printf("shmctl failed \n");
//        return -1;
//    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode Top 100 Liked Questions(序号236~347)

236. Lowest Common Ancestor of a Binary Tree 题意&#xff1a;二叉树&#xff0c;求最近公共祖先&#xff0c;All Node.val are unique. 我的思路 首先把每个节点的深度得到&#xff0c;之后不停向上&#xff0c;直到val相同&#xff0c;存深度就用map存吧 但是它没有向…

嵌入式Linux驱动开发(LCD屏幕专题)(二)

一、结合APP分析LCD驱动程序 1、open app: open("/dev/fb0", ...) 主设备号: 29, 次设备号: 0 -------------------------------------------------------------- kernel:fb_open // fbmem.cstruct fb_info *info;info get_fb_info(fbidx);if (info->fbop…

分布式系统常用的模式

分布式系统常用的模式 Ambassador 名称&#xff1a;“大使”模式 介绍&#xff1a;作为应用程序和其他服务的“中间人”&#xff0c;负责应用程序和其他服务之间的通信&#xff0c;包括日志、监控或重试处理等任务。 举例&#xff1a;K8S使用Envoy作为一个“大使”来简化服务…

【算法】堆排序 详解

堆排序 详解 堆排序代码实现 排序&#xff1a; 排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a; 假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c…

LeetCode每日一题:1123. 最深叶节点的最近公共祖先(2023.9.6 C++)

目录 1123. 最深叶节点的最近公共祖先 题目描述&#xff1a; 实现代码与解析&#xff1a; dfs 原理思路&#xff1a; 1123. 最深叶节点的最近公共祖先 题目描述&#xff1a; 给你一个有根节点 root 的二叉树&#xff0c;返回它 最深的叶节点的最近公共祖先 。 回想一下&…

【网络编程】TCP传输控制协议(Transmission Control Protocol)

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…

【FPGA】通俗理解从VGA显示到HDMI显示

注&#xff1a;大部分参考内容来自“征途Pro《FPGA Verilog开发实战指南——基于Altera EP4CE10》2021.7.10&#xff08;上&#xff09;” 贴个下载地址&#xff1a; 野火FPGA-Altera-EP4CE10征途开发板_核心板 — 野火产品资料下载中心 文档 hdmi显示器驱动设计与验证 — …

K8S的CKA考试环境和题目

CKA考试这几年来虽然版本在升级&#xff0c;但题目一直没有大的变化&#xff0c;通过K8S考试的方法就是在模拟环境上反复练习&#xff0c;通过练习熟悉考试环境和考试过程中可能遇到的坑。这里姚远老师详细向大家介绍一下考试的环境和题目&#xff0c;需要详细资料的同学请在文…

单片机-蜂鸣器

简介 蜂鸣器是一种一体化结构的电子讯响器&#xff0c;采用直流电压供电 蜂鸣器主要分为 压电式蜂鸣器 和 电磁式蜂鸣器 两 种类型。 压电式蜂鸣器 主要由多谐振荡器、压电蜂鸣片、阻抗匹配器及共鸣箱、外壳等组成。多谐振荡器由晶体管或集成电路构成&#xff0c;当接通电源后&…

HarmonyOS实现静态与动态数据可视化图表

一. 样例介绍 本篇Codelab基于switch组件和chart组件&#xff0c;实现线形图、占比图、柱状图&#xff0c;并通过switch切换chart组件数据的动静态显示。要求实现以下功能&#xff1a; 实现静态数据可视化图表。打开开关&#xff0c;实现静态图切换为动态可视化图表 相关概念 s…

基于SpringBoot的医院挂号系统

基于SpringBootVue的医院挂号、预约、问诊管理系统&#xff0c;前后端分离 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 角色&#xff1a;管理员、用户、医生 管…