进程通信——共享内存

原理

共享内存有点像动态库

创建共享内存:操作系统在物理内存分配一段空间(Shared Memory Segment)

将共享内存挂起:通过页表将共享内存映射到两个进程的共享区

通信:拿到虚拟地址,写端直接在地址上写数据,读端直接在地址上读数据

断开挂起,销毁共享内存

和文件一样,共享内存也会有对应的内核结构体来描述,有对应的共享内存描述符。

接口

创建共享内存

ftok

ftok是一个算法函数,目的是通过路径名和proj_id的计算,获取到一个共享内存的唯一标识key值

ftok不能保证获取的key值和已经存在的共享内存不同,如果出现冲突,需要对参数做适当修改,


shmget 

 

shmget可以通过key值创建/找到共享内存

size表示共享内存的大小,size大小尽量是内存块大小(4KB)的整数倍

shmflg是一个比特标志位的参数:

IPC_CREAT表示没有key对应的共享内存就创建,存在不创建

IPC_EXCL不单独使用,必须和IPC_CREAT一起用,表示如果已经存在对应的key所对应的共享内存就报错退出

mode,表示文件权限

shmid(共享内存描述符)和key都是共享内存的标识,二者有何区别?

key是操作系统层面的标识唯一性的值,而shmid是在进程层面标识唯一性的值


挂起和解除挂起

shmat

 一般情况下,shmaddr传nullptr,shmflg传0就可以了。返回的void*指针需要类型转换后使用

shmdt


销毁共享内存

shmctl

 这个函数的功能很多,介绍两种用法:

cmd是一个比特标志位的参数,可传参有很多。buf是一个输入型参数,它是一个结构体,结构体有很多共享内存的属性

cmd传IPC_RMID表示要销毁共享内存,buf直接传nullptr即可

cmd传IPC_STAT,buf传一个提前创建好的struct shmid_ds结构体指针即可,后面可以对buf结构体内容进行访问

共享内存销毁并不是直接销毁,操作系统会通过共享内存结构体的引用计数判断,只有当引用计数为0,才会真正销毁。否则本质都是让引用计数减1

共享内存特性

1.共享内存的生命周期是随内核的,用户不主动关闭,内存会一直存在,除非内核重启。

可以在进程使用结束后关闭,如果未能正常关闭:

使用ipcs -m查看当前所有内存块信息

ipcrm -m [shmid] 关闭内存

2.共享内存没有同步互斥类似的保护数据的机制,数据由用户维护

3.共享内存是所有进程通信中,速度最快的 

代码实例

//comm.hpp 包含客户端和服务端的头文件
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

//sever.cpp 服务端创建共享内存,读
#include "comm.hpp"
using namespace std;
int main()
{
    //Log log;
    // 创建共享内存
    key_t k = ftok("/home/ly/brilliant-alone/Linuxcode/IPC", 0x6666);
    int shmid = shmget(k,4096, IPC_CREAT|IPC_EXCL|0666);
    if(shmid < 0)
    {
        //cout << "shmget fail" <<  endl;
        cout << strerror(errno) <<  endl;
        return -1;
    }
    //挂到进程地址空间
    char* add = (char*)shmat(shmid, nullptr, 0);
    //读取
    while(1)
    {
        cout << "client say:" << add <<endl;
        sleep(1);
    }

    //断开挂起
    shmdt(add);
    //关闭
    shmctl(shmid, IPC_RMID, nullptr);
    return 0;
}

//client.cpp 客户端 写
#include "comm.hpp"
using namespace std;

int main()
{
    // 找shmid
    key_t k = ftok("/home/ly/brilliant-alone/Linuxcode/IPC", 0x6666);
    int shmid = shmget(k, 4096, IPC_CREAT);
    // 挂到进程地址空间
    char* add = (char*)shmat(shmid,nullptr,0);
    //写入
    while(1)
    {
        cout << "Input:";
        fgets(add, 4096, stdin);
    }
    shmdt(add);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值