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

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

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

1)优点
共享内存是进程间通信访问速度最快。
例如消息队列,FIFO,管道的消息传递方式一般为
1:服务器得到输入
2:通过管道,消息队列写入数据,通常需要从进程拷贝到内核。
3:客户从内核拷贝到进程
4:然后再从进程中拷贝到输出文件
上述过程通常要经过4次拷贝,才能完成文件的传递。
共享内存只需要两次拷贝
1:从输入文件到共享内存区
2:从共享内存区输出到文件
上述过程减少了数据不必要的拷贝,以及用户态和内核态之间的切换,所以花的时间较少,和访问进程独有的内存区域一样快

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

2.查看系统共享内存

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

image.png

3.函数API

1)获取共享内存

int shmget(key_t key, size_t size, int shmflg);

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

2)映射共享内存

 void *shmat(int shmid, const void *shmaddr, int shmflg);

shmid: 共享内存ID
shmaddr: 起始虚拟地址空间,NULL则是由系统自动分配
shmflag:一般为0,可以给SHM_RDONLY为只读模式,其他的为读写
返回值:成功返回虚拟地址,出错返回-1
fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动断开映射。进程结束后,连接的共享内存也会断开映射。

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

3)断开共享内存映射

int shmdt(const void *shmaddr);

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

4)控制共享内存

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端代码

#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端代码

#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,正常我们使用的话,一定要用信号量等手段,进行共享内存的保护

相关推荐

  1. linux c进程通信共享内存和信号量

    2024-04-02 05:12:02       18 阅读
  2. python线进程内存共享方式

    2024-04-02 05:12:02       34 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-02 05:12:02       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-02 05:12:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-02 05:12:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-02 05:12:02       20 阅读

热门阅读

  1. DHCP(动态主机配置协议)

    2024-04-02 05:12:02       20 阅读
  2. 《1w实盘and大盘基金预测 day14》

    2024-04-02 05:12:02       17 阅读
  3. DQL语言(数据库检索select)1

    2024-04-02 05:12:02       12 阅读
  4. android 13 相册和拍照问题

    2024-04-02 05:12:02       14 阅读
  5. 洛谷 P8783 [蓝桥杯 2022 省 B] 统计子矩阵

    2024-04-02 05:12:02       18 阅读
  6. 2.创建型模式--工厂模式

    2024-04-02 05:12:02       12 阅读
  7. 前端无痛刷新的方案

    2024-04-02 05:12:02       16 阅读
  8. React Umi国际化配置

    2024-04-02 05:12:02       15 阅读
  9. 大数据基础设施搭建 - Spark

    2024-04-02 05:12:02       14 阅读
  10. python的sort的key参数

    2024-04-02 05:12:02       16 阅读