Linux学习(21):共享内存

目录

1.共享内存的概念

2.共享内存的使用步骤 

3.函数介绍

3.1shmget函数进行创建

3.2shmat函数进行关联

3.3shmdt函数解除关联

3.4shmctl函数操作共享内存

4.一些常见的问题 


1.共享内存的概念

注意:共享内存是在用户区的

2.共享内存的使用步骤 

 shmget-->shmat--->shmdt-->shmctl

3.函数介绍

3.1shmget函数进行创建

int shmget(key_t key, size_t size, int shmflg);
- 功能:创建一个新的共享内存段,或者获取一个既有的共享内存段的标识。
    新创建的内存段中的数据都会被初始化为0
- 参数:
    - key : key_t类型是一个整形,通过这个找到或者创建一个共享内存。
            一般使用16进制表示,非0值
    - size: 共享内存的大小,size应该按页对齐:由于操作系统中管理物理内存时一般以页面(page)为单位进行划分和管理,
            所以建议将size按照页面大小来对齐。例如,在Linux系统中,页面的大小通常是4KB或者8KB。
    - shmflg: 属性
        - 设置访问权限
        - 附加属性:创建/判断共享内存是不是存在
            - 创建:IPC_CREAT
            - 判断共享内存是否存在: IPC_EXCL , 需要和IPC_CREAT一起使用
                IPC_CREAT | IPC_EXCL | 0664
    - 返回值:
        失败:-1 并设置错误号
        成功:>0 返回共享内存的引用的ID,后面操作共享内存都是通过这个值。
        注意,key是名字,返回值是身份证号shmid,不是相等的。

3.2shmat函数进行关联

void *shmat(int shmid, const void *shmaddr, int shmflg);
- 功能:和当前的进程进行关联
- 参数:
    - shmid : 共享内存的标识(ID),由shmget返回值获取
    - shmaddr: 申请的共享内存的起始地址,设置为NULL,内核指定
    - shmflg : 对共享内存的操作
        - 读 : SHM_RDONLY, 必须要有读权限
        - 读写: 0
- 返回值:
    成功:返回共享内存的首(起始)地址。  失败(void *) -1

3.3shmdt函数解除关联

int shmdt(const void *shmaddr);
- 功能:解除当前进程和共享内存的关联
- 参数:
    shmaddr:共享内存的首地址
- 返回值:成功 0, 失败 -1

3.4shmctl函数操作共享内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- 功能:对共享内存进行操作。删除共享内存,共享内存要删除才会消失,创建共享内存的进程被销毁了对共享内存是没有任何影响。
- 参数:
    - shmid: 共享内存的ID
    - cmd : 要做的操作
        - IPC_STAT : 获取共享内存的当前的状态
        - IPC_SET : 设置共享内存的状态
        - IPC_RMID: 标记共享内存被销毁
    - buf:需要设置或者获取的共享内存的属性信息
        - IPC_STAT : buf存储数据,传出参数
        - IPC_SET : buf中需要初始化数据,设置到内核中,传入参数
        - IPC_RMID : 没有用,NULL
shmctl(id,IPC_RMID,NULL)表示删除

注意:创建共享内存的进程被销毁了对共享内存是没有任何影响。

4.一些常见的问题 

1.操作系统如何知道一块共享内存被多少个进程关联?

共享内存维护了一个结构体struct shmid_ds 这个结构体中有一个成员 shm_nattch记录了关联的进程个数

 2.可不可以对共享内存进行多次删除 shmctl

可以,因为shmctl只是标记删除,当和共享内存关联的进程数为0时才真正删除

标记后key变为0,表示标记删除,如果一个进程和共享内存取消关联,那么这个进程就不能继续操作这个共享内存。也不能进行关联。标识符发生了变化,表示不能进行新的映射连接

3.共享内存和内存映射的区别

--共享内存可以直接创建,而内存映射需要磁盘文件(匿名映射除外)

--共享内存的效率更高

--共享内存:所有的进程使用一块内存;内存映射:每个进程在自己的虚拟地址空间中有一个独立的内存,他们映射一块磁盘中的内存

--如果进程突然退出:共享内存还存在内存映射消失

--运行进程的电脑死机:共享内存中的数据消失,内存映射区的数据由于磁盘内存还在,保留

--进程退出,内存映射区销毁;进程退出,共享内存还在,标记删除,如果一个进程退出,会自动和共享内存进行取消关联。

测试代码:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
//write.c
int main() {    

    // 1.创建一个共享内存
    int shmid = shmget(100, 4096, IPC_CREAT|0664);
    printf("shmid : %d\n", shmid);
    
    // 2.和当前进程进行关联
    void * ptr = shmat(shmid, NULL, 0);

    char * str = "helloworld";

    // 3.写数据
    memcpy(ptr, str, strlen(str) + 1);//放'\0'

    printf("按任意键继续\n");
    getchar();//等待

    // 4.解除关联
    shmdt(ptr);

    // 5.删除共享内存
    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}
//read.c
int main() {

    // 1.获取一个共享内存
    int shmid = shmget(100, 0, IPC_CREAT);//一般写0表示获取,不能大于设置的大小
    printf("shmid : %d\n", shmid);

    // 2.和当前进程进行关联
    void* ptr = shmat(shmid, NULL, 0);

    // 3.读数据
    printf("%s\n", (char*)ptr);

    printf("按任意键继续\n");
    getchar();

    // 4.解除关联
    shmdt(ptr);

    // 5.删除共享内存
    shmctl(shmid, IPC_RMID, NULL);

    return 0;
}

注意:在读进程中,int shmid = shmget(100, 0, IPC_CREAT);//一般写0表示获取,不能大于设置的大小

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值