Linux多进程通信(3)——详细说说共享内存原理及使用例程

1.共享内存原理及优缺点

共享内存的原理便是将相同的一片物理内存映射到进程A和进程B不同的逻辑地址空间,两个进程同时访问这块物理内存(共享内存)。

1)优点

共享内存是进程间通信访问速度最快。

例如消息队列,FIFO,管道的消息传递方式一般为

1:服务器得到输入

2:通过管道,消息队列写入数据,通常需要从进程拷贝到内核。

3:客户从内核拷贝到进程

4:然后再从进程中拷贝到输出文件

上述过程通常要经过4次拷贝,才能完成文件的传递。

共享内存只需要两次拷贝

1:从输入文件到共享内存区

2:从共享内存区输出到文件

上述过程减少了数据不必要的拷贝,以及用户态和内核态之间的切换,所以花的时间较少,和访问进程独有的内存区域一样快

2)缺点

共享内存是进程间不安全的,需要使用额外的同步进制来控制对共享内存的访问,常用的是信号量。

2.查看系统共享内存

c 复制代码
ipcs -m    //查看系统的共享内存
ipcrm -m [shmid] //删除指定共享内存段

3.函数API

1)获取共享内存

c 复制代码
int shmget(key_t key, size_t size, int shmflg);

key :ftok生成的key标识,在系统中是唯一的
size :共享内存大小(系统申请内存的最小单位是页,一页是4K字节,为了避免大量的碎片,申请内存大小一般是页的整数倍),为0代表只是获取已经创建好的共享内存
shmflag :和信号量等相同,IPC_CREAT | IPC_EXCL则代表不存在则创建,存在则返回失败,0代表获取共享内存标识符,若不存在则函数会报错。

2)映射共享内存

c 复制代码
 void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid: 共享内存ID
shmaddr : 起始虚拟地址空间,NULL则是由系统自动分配
shmflag :一般为0,可以给SHM_RDONLY为只读模式,其他的为读写
返回值 :成功返回虚拟地址,出错返回-1

fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动断开映射。进程结束后,连接的共享内存也会断开映射。

必须所有映射到共享内存的进程都断开映射,才会删除这片共享内存!

3)断开共享内存映射

c 复制代码
int shmdt(const void *shmaddr);

shmdt : 断开共享内存映射(断开不代表删除共享内存,只是断开映射的线路)
shmaddr:共享内存地址

4)控制共享内存

c 复制代码
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

shmid: 共享内存ID
cmd :执行的具体操作

IPC_RMID:表示可以删除共享内存

IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中

IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
buf :共享内存管理的结构体
必须所有映射到共享内存的进程都断开映射,才会删除这片共享内存!

4.例程

1)write端代码

c 复制代码
#include "apue.h"
#include <sys/ipc.h>
#include <sys/shm.h>
//write hello world 
//another program read this msg

int main(int argc, char **argv)
{
    //1.根据文件和id获取key
    key_t key;
    key = ftok(".", 2);

    //2.根据key创建共享存储区
    int shmid = 0;
    shmid = shmget(key, 1024, IPC_CREAT|IPC_EXCL|0666);
    if (shmid == -1) {
        perror("shmget error");
        return -1;
    }

    //3.连接共享存储区和进程地址空间
    char *shmaddr = NULL;
    shmaddr = shmat(shmid, 0, 0);
    if (shmaddr == (char *)-1) {
        perror("shmat error");
        return -1;
    }

    //4.写入数据
    strcpy(shmaddr, "hello world");

    sleep(5);

    //5. 断开共享存储连接
    shmdt(shmaddr);
    //6. 删除共享存储区
    shmctl(shmid, IPC_RMID, NULL);

    printf("success write!!\n");
    return 0;
}

2)read端代码

c 复制代码
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
//write hello world 
//another program read this msg

int main(int argc, char **argv)
{
    //1.根据文件和id获取key
    key_t key;
    key = ftok(".", 2);

    //2.根据key创建共享存储区
    int shmid = 0;
    shmid = shmget(key, 0, 0);
    if (shmid == -1) {
        perror("shmget error");
        return -1;
    }

    //3.连接共享存储区和进程地址空间
    char *shmaddr = NULL;
    shmaddr = shmat(shmid, 0, 0);
    if (shmaddr == (char *)-1) {
        perror("shmat error");
        return -1;
    }

    printf("read data is %s \n", shmaddr);

    //5. 断开共享存储连接
    shmdt(shmaddr);

    printf("success read!!\n");
    return 0;
}

gcc编译后测试效果如下~,当然这只是一个简单的demo,正常我们使用的话,一定要用信号量等手段,进行共享内存的保护

相关推荐
C+-C资深大佬7 分钟前
python while循环
服务器·开发语言·python
Tian_Hang7 分钟前
eclipse ditto 学习笔记
运维·服务器·开发语言·javascript·3d
iCxhust22 分钟前
linux目录是否保存在硬盘 启动后读入解析的
linux·运维·服务器
懒鸟一枚22 分钟前
Linux 系统 Service 服务配置详解
linux·服务器·网络
livemetee36 分钟前
【关于Spring声明式事务】
java·后端·spring
倒流时光三十年39 分钟前
Java 内存模型(JMM)通俗解释
java·开发语言
敖行客 Allthinker1 小时前
企业级多台服务器组装 K3s 高性能集群实战指南
运维·服务器·团队开发
RisunJan1 小时前
Linux命令-readonly(Bash 内建设置只读变量)
linux
码兄科技1 小时前
Java AI智能体开发实战:从零构建企业级智能应用指南
java·开发语言·人工智能
2401_859506241 小时前
AIGC赋能大漆摆件设计:从痛点分析到技术架构与实战验证
java·大数据·人工智能