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

news2024/11/28 20:45:33

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 segment
    if((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 VALUE
       On success, shmat() returns the address of the attached shared memory segment; on error, (void *) -1 is returned, and
       errno 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 must
                 be 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.mode
                 field 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  in
                 will 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 segment
    if ((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.coloradmin.cn/o/987313.html

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

相关文章

Redis持久化、主从与哨兵架构详解

Redis持久化 RDB快照&#xff08;snapshot&#xff09; 在默认情况下&#xff0c; Redis 将内存数据库快照保存在名字为 dump.rdb 的二进制文件中。 你可以对 Redis 进行设置&#xff0c; 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时&#xff0c; 自动保存一次数…

yolov7添加pconv模块

连接pconv 1、复制到models-common.py文件最后 2、添加模块到yolo.py 3、修改网络&#xff0c;建议替换3x3的卷积&#xff0c;后面的参数不要了 4、不能替换步长为2的卷积

CSS笔记(黑马程序员pink老师前端)浮动,清除浮动

浮动可以改变标签的默认排列方式。浮动元素常与标准流的父元素搭配使用. 网页布局第一准则:多个块级元素纵向排列找标准流&#xff0c;多个块级元素横向排列找浮动。 float属性用于创建浮动框&#xff0c;将其移动到一边&#xff0c;直到左边缘或右边缘触及包含块或另一个浮动框…

【算法系列篇】分治-快排

文章目录 前言什么是分冶1.颜色分类1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 排序数组2.1 题目要求2.2 做题思路2.3 Java代码实现 3.数组中的第k个最大元素3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 最小的k个数4.1 题目要求4.2 做题思路4.3 Java代码实现 总结 前言 …

前端面试题合集(一)

前端面试题合集 1.js异步方案2.文件上传如何限制文件类型3. 说出 与的区别4.多维数组如何降维5.如何给一个按钮绑定两个onclick事件 1.js异步方案 js异步方法分为两种&#xff0c;分别为defer和async,如果没有写其中一种的话代码从上到下同步执行&#xff0c;遇到脚本代码之后…

埋头干活不会汇报,别说 996 就算 007 也没用!

​ 见字如面&#xff0c;我是军哥&#xff01; 经调研发现 80% 的程序员认为工作汇报就是形式主义&#xff0c;无聊至极&#xff0c;但是我要和你说&#xff0c;做好工作汇报非常重要&#xff0c;这直接关系到你在这家公司能否快速成长和晋升加薪&#xff0c;而且要告诉你一件扎…

vue3:18、Pinia持久化(pinia-plugin-persistedstate)

安装插件 npm i pinia-plugin-persistedstate main.js中引入 import { createApp } from vue import { createPinia } from pinia import App from ./App.vue import piniaPluginPersistedstate from pinia-plugin-persistedstate // createApp(App).use(CreatePinia()).mou…

Day58|leetcode 739. 每日温度、496.下一个更大元素 I

今天开始单调栈&#xff01; leetcode 739. 每日温度 题目链接&#xff1a;739. 每日温度 - 力扣&#xff08;LeetCode&#xff09; 视频链接&#xff1a;单调栈&#xff0c;你该了解的&#xff0c;这里都讲了&#xff01;LeetCode:739.每日温度_哔哩哔哩_bilibili 题目概述 …

Unity——脚本与导航系统

Unity内置了一个比较完善的导航系统&#xff0c;一般称为Nav Mesh&#xff08;导航网格&#xff09;&#xff0c;用它可以满足大多数游戏中角色自动导航的需求。 一、导航系统相关组件 Unity的导航系统由以下几个部分组成&#xff1a; Nav Mesh。Nav Mesh与具体的场景关联&…

【postgresql 基础入门】数据库服务的管理,启动、停止、状态查看、配置加载、重启都在这里

数据库服务管理 ​专栏内容&#xff1a; postgresql内核源码分析手写数据库toadb并发编程 ​开源贡献&#xff1a; toadb开源库 个人主页&#xff1a;我的主页 管理社区&#xff1a;开源数据库 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff…

【精读Uboot】反汇编分析SPL的_main函数

1、简介 典型的Uboot启动分为两个阶段&#xff0c;bootrom->SPL&#xff08;Secondary Program Loader&#xff09;->ATF->OPTEE(可选)->Uboot。其中SPL为BL2&#xff0c;ATF为BL31&#xff0c;OPTEE为BL32&#xff0c;Uboot为BL33。其中bootrom是固化在芯片内部的…

MySQL 8.0.34(x64)安装笔记

一、背景 从MySQL 5.6到5.7&#xff0c;再到8.0&#xff0c;版本的跳跃不可谓不大。安装、配置的差别也不可谓不大&#xff0c;特此备忘。 二、过程 &#xff08;1&#xff09;获取MySQL 8.0社区版&#xff08;MySQL Community Server&#xff09;   从 官网 字样 “MySQL …

3D印刷电路板在线渲染查看工具

从概念上讲&#xff0c;这是有道理的&#xff0c;因为PCB印制电路板上的走线从一个连接到下一个连接的路线基本上是平面的。 然而&#xff0c;我们生活在一个 3 维世界中&#xff0c;能够以这种方式可视化电路以及相应的组件&#xff0c;对于设计过程很有帮助。本文将介绍KiCad…

VsCode Ctrl+.修复无效

vscode 快速修复(quick fix) 快捷键(Ctrl .)被占用问题解决方法_vscode快速修复快捷键_追求者2016的博客-CSDN博客

Android 系统源码目录frameworks/base/packages和packages/apps下的APP区别

概要 在 Android Open Source Project (AOSP) 源代码中&#xff0c;frameworks/base/packages 和 packages/apps 目录都包含 Android 系统中的应用程序&#xff0c;但它们在性质和用途上有一些区别&#xff1a; 1&#xff0c;frameworks/base/packages frameworks/base 目录…

OMRON G9SP和NB触摸屏使用232口通讯

G9SP和NB触摸屏使用232口通讯 实验时间&#xff1a;2023/9/7 实验设备&#xff1a;G9SP-N20S、CP1W-CIF01&#xff08;232串口选减板&#xff09;、NB5Q-TW00B、XW2Z-200T&#xff08;串口线&#xff09;&#xff0c;CP1W-20EDT1&#xff0c;D4GS-N4T&#xff08;安全门开关&a…

alibaba国际版阿里巴巴API接入说明(阿里巴巴商品详情+关键词搜索商品列表)

API地址:https://o0b.cn/anzexi 调用示例&#xff1a;https://api-gw.onebound.cn/alibaba/item_get/?keytest_api_key& &num_iid60840463360&&langzh-CN&secret 参数说明 通用参数说明 url说明 https://api-gw.onebound.cn/平台/API类型/ 平台&#xf…

Golang 方法使用的注意事项和细节

方法的声明(定义) furie (recevier type) methodName (参数列表) (返回值列表){方法体return返回值 } 1)参数列表&#xff1a;表示方法输入 2) recevier type:表示这个方法和type这个类型进行绑定&#xff0c;或者说该方法作用于type类型 3) receiver type:type可以是结构体…

mysql 安全加固

PS&#xff1a;之前在做安全测试的时候&#xff0c;报告mysql有安全漏洞&#xff0c;于是研究了下如何修复&#xff0c;于是记录下来分享给大家 1.1修改mysql 存放位置 修复 1.停服务 service mysqld stop2.迁位置 2.1 新建迁移目录 mkdir /home/database2.2 迁移数据文件…

深入探索KVM虚拟化技术:全面掌握虚拟机的创建与管理

文章目录 安装KVM开启cpu虚拟化安装KVM检查环境是否正常 KVM图形化创建虚拟机上传ISO创建虚拟机加载镜像配置内存添加磁盘能否手工指定存储路径呢&#xff1f;创建成功安装完成查看虚拟机 KVM命令行创建虚拟机创建磁盘通过命令行创建虚拟机手动安装虚拟机 KVM命令行创建虚拟机-…