IPC_共享内存

1. 共享内存的定义

共享内存就是允许多个不相关的进程访问同一个逻辑内存,共享内存是在两个正在运行的进程之间共享和传递数据的一种非常邮箱的方式,不同进程之间共享的内存通常安排为同一物理内存,进程可以将同一段内存连接到他们自己的地址空间中,所有进程都可以访问共享内存中的地址。而如果某个进程向共享内存中写入数据,所做的改动将立即影响到同一段共享内存的任何其他进程。

2. 共享内存的使用
  1. 调用函数shmget创建一个新共享内存或者取得一个既有共享内存段的标识符
  2. 调用shmat将共享内存附加到当前进程的虚拟地址空间中
  3. 为了引用共享内存,程序需要由shmat函数返回的addr值,这个是一个指向进程的虚拟地址空间中该共享内存段起点的指针。
  4. 调用shmdt分离共享内存段
  5. 调用函数shmctl删除共享内存段
3. 面试题:
3.1. 超过共享内存大小限制怎么办。

在linux服务器上,共享内存的总体大小是有限制的。这个大小可以通过SHMMAX参数来定义,SHNMAX的默认大小为32M

3.2 同一个进程多次进行shmat会出现什么问题

当首次创建共享内存段时,它不能被任何进程所访问,为了使共享内存区可以被访问,则必须通过shmat函数将其附加到自己的进程空间中。这样进程就与共享内存建立了连接。
这样挂载一个共享内存如果是第一次调用时没有问题的,但是一个进程是可以对同一个共享内存多次shmat进行挂载的,物理内存是指向同一块,如果shmaddr为NULL,则每次返回的线性地址空间都不同,而且指向这块共享内存的引用计数会增加,也就是进程多块线性空间会指向同一块物理地址,这样会一直消耗进程的虚拟内存空间,很有可能会最后导致进程线性空间被使用完,而导致下次shmat或者其他操作失败。

4. 共享内存demo
// ShmWrite.cpp
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/ipc.h>

#define BUFFER 4096

int main(int argc, char *argv[])
{
    // 创建一个新的共享内存段或者取得一个已有共享内存段的标识符
    int shmid = shmget((key_t)123456, BUFFER, S_IRUSR|S_IWUSR | IPC_CREAT | IPC_EXCL);
    if (shmid == -1)
    {
        perror("shmget");
        exit(1);
    }
    printf("shmid = %d\n",shmid);
    // 将共享内存段加载到调用进程的虚拟地址空间中
    char* shmaddr = (char *)shmat(shmid, NULL, 0);
    if (shmaddr == (void*)-1)
    {
        perror ("shmat");
        exit(1);
    }
    // 从标准输入读数据
    fgets(shmaddr, 100, stdin);
    // 分离共享内存段
    if (shmdt(shmaddr) == -1)
    {
        perror("shmdt");
        exit(1);
    }
    sleep(10); // 睡眠十秒后共享内存失效
    // 删除这块共享内存
    if (shmctl(shmid, IPC_RMID, NULL) == -1)
    {
        perror("shmctl");
        exit(1);
    }
    return 0;
}
// ShmRead.cpp
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/stat.h>
#include <sys/shm.h>

#define BUFFER 4096

int main(int argc,char **argv)
{
    int shmid = shmget((key_t)123456, BUFFER, S_IRUSR|S_IWUSR);
    if (shmid == -1)
    {
        perror("shmget");
        exit(1);
    }
    char* shmaddr = (char *)shmat(shmid, NULL, 0);
    if (shmaddr == (void*)-1)
    {
        perror("shmat");
        exit(1);
    }
    // 输出从另一个进程传过来的数据
    printf("%s\n", shmaddr);
    if (shmdt(shmaddr) == -1)
    {
        perror("shmdt");
        exit(1);
    }
    return 0;
}
5. 总结
  • 优点:
    • 采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于管道和消息队列而言,则需要在内核和用户空间进行四次数据拷贝,而共享内存只拷贝两次数据,一次从输入文件到共享内存区,另一次从共享内存区到输出文件。
    • 共享内存可以用于任意两个进程之间的通信
  • 缺点:
    • 共享内存没有提供同步机制,需要借助其他手段进行进程间的同步工作、
    • 利用内存缓冲区之间交换信息,只能同一个计算机系统内的诸多进程共享。

参考:
https://www.cnblogs.com/wuchanming/p/4381910.html
https://blog.csdn.net/echo_ana/article/details/53456543
https://blog.csdn.net/daaikuaichuan/article/details/82832073

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值