Linux基础内容(20)—— 共享内存

Linux基础内容(19)—— 进程间通信(介绍与管道内容)_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130034918?spm=1001.2014.3001.5502

目录

1.共享内存的原理

2.共享内存的概念和特点

创建共享内存 

共享内存的形式

共享内存(ipc资源)的调用和特征

用户接口删除共享内存

共享内存关联

去关联

特点

共享内存大小


1.共享内存的原理

1.由于进程本身的结构 --- 虚拟内存地址空间,使得进程间互相看不见对面的物理内存地址,达不到进程间直接通信的目的

2.但如果OS能提供一个接口,这个接口是用户调用之可以构建出共享的内存,并且共享内存的地址通过页表映射到虚拟地址空间中,两个进程如果都这里映射了同一个共享内存,那么就可以达到进程间通信的目的

 3.如果不想通信了,需要切断两边的映射(去关联)和释放共享内存

理解:

1.进程间通信是专门设计的,用户只需要调用接口

2.共享内存是一种通信方式,所有想通信的进程都可以用

3.OS中一定可能同时存在多个共享内存

2.共享内存的概念和特点

通过让不同的进程看到同一块内存块,这样的内存称之为共享内存

创建共享内存 

size:申请多大的共享内存

key:能进行唯一性表示的数,具体内容不重要,看到同一个key就可以看到同一个资源了

shmflg:

IPC_CREAT -- 指定的共享内存,不存在,创建;存在,共享内存标志返回

IPC_EXCL -- 无法单独使用;只有当 IPC_CREAT|IPC_EXCL 同时使用,如果不存在,创建,如果存在,出错返回

返回值:成功返回共享内存的标识符,失败返回-1

注意:创建时还得把共享内存的权限属性给传入

转换得到key值

pathname:一个字符串

proj_id:一个数字

这样组合出唯一的数字key返回

返回:成功返回key值,失败-1

共享内存的形式

1.c语言中malloc函数需要输入大小,但是free反而不需要。这是因为malloc函数不会只给我们申请指定大小空间,它一定要申请更大的空间来存储它的属性方便管理

2.关于以前进程的也是先描述再组织

3.那么对于共享内存,也是如此,我们不会只申请指定大小就结束了,我们还会存储共享内存的相关属性,这样方便管理,那么对于共享内存而言:物理内存存储块+共享内存属性

4.上面说过,共享内存可能有很多,那么如何表示唯一性呢?答案很明显,key就是唯一的,那么创建时我们能通过key得到唯一的共享内存。

5.那么key也是一种属性,所以这个key也被放在描述共享内存的属性之中。

6.那么链接共享内存就是通过得到一样的key,在组织数据结构中遍历找每个内存属性中放key的值,找到了就唯一指定了,key是内核级别的属性

7.shmid和key的关系是:shmid是在用户级别调用的数值。其区别就于fd和inode类似,inode内核级别表示文件的唯一性,而用户直接不使用inode,而是调用函数返回的fd进行操作

共享内存(ipc资源)的调用和特征

1.共享内存的生命周期随着OS的,不随进程而消除(system V特性)

 2.ipcs -m查看共享内存

perm:文件权限

nattch:关联的进程

3.ipcrm -m shmid删除共享内存

3.ipcs -q查看消息队列

4. ipcs -s查看信号量

用户接口删除共享内存

该接口是对共享内存进行控制,控制里包括删除

shmid:指定shmid

cmd:指令

IPC_STAT

IPC_SET

IPC_RMID:立即移除共享内存

buf:获取属性存储空间,不要则输入nullptr

返回值:失败则-1

删除该共享内存的前提就是将内存与进程相关联,毕竟调用系统接口删除的前提是有这块地址

共享内存关联

用于映射到虚拟地址空间的哪个位置中

后两位数指定位置,一般不指定:设为nullptr和0

返回值:共享内存地址空间的返回值

失败是返回-1

去关联

shmdt()

 返回0成功,-1失败

特点

优点:所以进程间通信中速度最快的

因为我们写入共享内存,另一方就能得到,能大大减少拷贝的次数

同样的代码用来通信,(单纯的收发消息)需要拷贝几次才能完成任务:

管道实现:4+2次

共享内存实现:2+2次

缺点:不给我们进行同步互斥消息的,没有对数据做任何保护

共享内存大小

建议是4KB的整数倍

因为系统分配共享内存是以4KN为单位的 -- 内存划分内存块的基本单位

给大给小都会向上取整:使用的内存显示为申请的,但是内存中的确开辟,只是用户调不到

comm.hpp
#ifndef _COMM_HPP_
#define _COMM_HPP_

#include <iostream>
#include <cstdio>
#include <cerrno>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>

#define PATHNAME "."
#define PROJ_ID 0x66
#define MAX_SIZE 4096

key_t getKey()
{
    key_t k = ftok(PATHNAME, PROJ_ID);
    if (k < 0)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(1);
    }
    return k;
}

int getShmHelper(key_t k, int flags)
{
    int shmid = shmget(k, MAX_SIZE, flags);
    if(shmid<0)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(2);
    }
    return shmid;
}

int creatShm(key_t k)
{
    return getShmHelper(k, IPC_CREAT | IPC_EXCL | 0600); // 创建一个新的,所以如果没有就判错
}

int getShm(key_t k)
{
    return getShmHelper(k, IPC_CREAT /*0*/); // 调用创建的,0也可以
}

void* attchShm(int shmid)
{
    void* mem = shmat(shmid,nullptr,0);
    if((long long)mem==-1L)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(3);
    }
    return mem;
}

void detachShm(void* start)
{
    if(shmdt(start)==-1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
    }
}

void deleteShm(int shmid)
{
    if(shmctl(shmid,IPC_RMID,nullptr)==-1)
    {
        std::cerr << errno << ":" << strerror(errno) << std::endl;
        exit(1);
    }
}

#endif

server.cc
#include "comm.hpp"

int main()
{
    key_t k = getKey();
    printf("0x%x\n",k);
    int shmid = creatShm(k);
    printf("shmid:%d\n",shmid);

    sleep(5);

    char* start = (char*)attchShm(shmid);
    printf("attach success, adress start: %p\n",start);

    //使用
    while(true)
    {
        shmid_ds ds;
        shmctl(shmid,IPC_STAT,&ds);
        printf("获取信息: size:%d ,pid: %d ,myself: %d",ds.shm_segsz,ds.shm_cpid,getpid());
        printf("client say:%s\n",start);
        sleep(1);
    }

    //去关联
    detachShm(start);

    //删除
    deleteShm(shmid);
    return 0;
}

client
#include "comm.hpp"

int main()
{
    key_t k = getKey();
    printf("0x%x\n",k);
    int shmid = getShm(k);
    printf("shmid:%d\n",shmid);

    sleep(5);
    char* start = (char*)attchShm(shmid);

    const char* message = "hello server,我是另一个进程";
    pid_t id = getpid();
    int cnt = 1;
    //char* buffer[1024];
    while(true)
    {
        snprintf(start,MAX_SIZE,"%s[pid:%d][消息编号%d]",message,id,cnt);
        //snprintf(buffer,sizeof(buffer),"%s[pid:%d][消息编号%d]",message,id,cnt);
        //memcpy(start,buffer,strlen(buffer)+1);
        // pid,count,mess
    }
    

    detachShm(start);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灼榆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值