【Linux】进程间通信---共享内存

共享内存 

    基于共享存储区的通信方式, 为了传输大量数据, 在内存中划出了一块共享存储区域, 通信的进程都可以对这块内存进行操

作, 通过对该内存的读或写交换信息, 实现通信, 这种通信属于高级通信, 通信的进程在通信前先向系统申请一块空间, 然后将

这块空间映射到自己的虚拟地址空间中, 使用完成后不再需要的话再将归还给系统

    共享内存是所有进程间通信方式中最快的一种

那么为什么共享内存是最快的呢?

    共享内存是将同一块物理内存映射到自己的虚拟地址空间中,  实现对相同的一块物理内存进行操作,  通过这种方式实现多

个进程间的数据共享功能,  少了两次用户态与内核间的数据拷贝过程,  所以最快.

注意:

    1. 管道生命周期随内核

    2. 共享内存是不受保护的, 多个进程同时操作的时候可能会造成混乱, 需要通过同步与互斥进行保护

操作步骤:

  1. 创建共享内存                                     shmget()

  2. 将共享内存映射到虚拟地址空间        shmat()

  3. 对这块空间进行操作                          memcpy

  4. 不使用了就解除映射关系                   shmdt()

  5. 删除共享内存                                     shmctl()

共享内存函数

  1. 创建共享内存(在内存中创建一块共享内存)

int shmget(key_t key, size_t size, int shmflg);
参数:
    key   : 共享内存标识符
          可以使用define宏定义, 也可以使用ftok函数进行生成, 但是一般推荐使用define更好一点
    size  : 共享内存大小
    shmflg: 选项标志
      IPC_CREAT    共享内存不存在则创建, 存在则打开
      IPC_EXCL     与IPC_CREAT同用, 共享内存存在则报错
      shm_mode     权限
返回值: 
    标识符(代码中的操作句柄)    失败:-1

   注意: shmflg是权限标志构成, 对权限不清楚的可以参考Linux---权限, 先了解了解权限 

  2. 建立映射(将共享内存与当前进程绑定在一起, 将共享内存段连接到进程地址空间)

void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
    shmid  : 标识符
    shmaddr: 置空-映射首地址由操作系统分配
    shmflg : 映射成功后的操作权限
      SHM_RDONLY  只读              
      0           默认-可读可写
返回值:
    映射首地址    失败返回:-1

  3. 解除映射(将共享内存与当前进程脱离)

int shmdt(const void *shmaddr);
  shmaddr:     映射首地址
返回值:
    成功:0    失败:-1

   注意: 脱离不等于删除, 就相当于你的QQ号码和你的微信号关联了, 现在你不想要这个QQ号码了, 现在先解除关联, 但是你的QQ号码并没有消失, 你还得注销这个QQ号码

  4. 控制共享内存(可以删除共享内存)

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
      shmid:   操作句柄
      cmd  :   操作类型
          IPC_RMID    删除共享内存
          IPC_STAT    把shmid_ds结构中的数据设置为共享内存的当前关联值
          IPC_SET     在进程中有权限的前提下, 把共享内存的当前关联设置为shmid_ds中给出的值
      buf  :   设置/获取共享内存信息
  共享内存不会被直接删除, 而是判断当前映射连接数是否为0
      为0:    直接删除
    不为0:    拒绝后续其它进程的映射连接, 当映射连接数为0时自动删除

实现通信:

shm_write.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/shm.h>
#define IPC_KEY 0x12345678

int main()
{
    //1. 创建共享内存
    int shmid = shmget(IPC_KEY, 32, IPC_CREAT | 0664); 
    if(shmid < 0)
    {
        perror("shmget error");
        return -1;
    }

    //2. 建立映射
    char* shm_start = shmat(shmid, NULL, 0);
    if(shm_start == (void*)-1)
    {
        perror("shmat error");
        return -1;
    }

    //3.操作
    int i = 0;
    while(1)
    {
        sprintf(shm_start, "这是一片博客---+%d\n",i++);
        sleep(1);
    }

    //4.解除映射
    shmdt(shm_start);

    //5.删除共享内存
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}
shm_read.c

只在第三步操作时候做出了修改

    //3.操作
    int i = 0;
    while(1)
    {
        printf("%s", shm_start);
        sleep(1);
    }

运行:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值