IPC----共享内存

本文详细介绍了共享内存的概念及其在进程间通信中的应用。包括共享内存的建立过程、关键函数的使用方法,以及通过示例代码展示了如何创建、映射和删除共享内存。此外,还讨论了共享内存的特点和System V IPC通信的优点与局限。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是共享内存:共享内存允许两个或多个进程访问给定的同一块存储区域。已知当一个进程被启动时,系统会为其创建一个 0~4G 的虚拟内存空间, 根据虚拟地址与物理地址之间的映射关系,进程可以通过操作虚拟地址,实现对物理页面的操作。
一般情况下,每个进程的虚拟地址空间会与不同的物理地址进行映射,但是当使用共享内存进行通信时,系统会将同一段物理内存映射给不同的进程。
两个进程的虚拟地址空间与共享内存之间的映射关系如下图
这里写图片描述
系统中的物理内存和虚拟内存都通过页面来管理,为多个进程分配共享内存,实际是为进程分配一个或多个物理页面,因此,共享内存的大小必须是系统中页面大小的整数倍
2.共享内存建立的过程
<1>首先将虚拟内存空间与共享
内存进行映射,
<2>映射完成后,进程对虚拟地址的读写,就相当于直接对物理内存
的读写。
<3>另外,与申请堆空间类似,当通信完成之后,也应释放物理内存,解除进程与共享内存的映射关系。
3.共享内存有关的函数

1.int shmget(key_t key, size_t size, int shmflg);
//功能是创建一块新的共享内存,或打开一块已经存在的共享内存
//第一个参数key,代表共享内存的键值
//第二个参数size用于设置共享内存的大小
//第三个参数 shmflg 用于设置 shmget()函数的创建条件(一般设置为 IPC_CREAT 或 IPC_EXCL)及进程对共享内存的读写权限。
2.void *shmat(int shmid, const void *shmaddr, int shmflg);
//功能是进行地址映射,将共享内存映射到进程虚拟地址空间中
//第一个参数 shmid 为共享内存标识符,该标识符一般由shmget()函数返回;
//参数 shmaddr 为一个指针类型的传入参数,用于指定共享内存映射到虚拟内存时的虚拟地址,当设置为 NULL 时,映射地址由系统决定;
//参数 shmflg 用于设置共享内存的使用方式,若 shmflg 设置为 SHM_RDONLY,则共享内存将以只读的方式进行映射,当前进程只能从共享内存中读取数据。
3.int shmdt(const void *shmaddr);
//功能是解除物理内存与进程虚拟地址空间的映射关系
4.int shmctl(int shmid, int cmd, struct shmid_ds *buf);
//功能是对已存在的共享内存进行操作,具体的操作由参数决定
//参数 shmid 表示共享内存标识符;
//参数 cmd 表示要执行的操作,常用的设置为IPC_RMID,功能为删除共享内存;
//参数 buf 用于对共享内存的管理信息进行设置,该参数是一个结构体指针,
5.struct shmid_ds *buf结构体如下
struct shmid_ds {
struct ipc_perm shm_perm; //所有者和权限标识
size_t shm_segsz; //共享内存大小
time_t shm_atime; //最后映射时间
time_t shm_dtime; //最后解除映射时间
time_t shm_ctime; //最后修改时间
pid_t shm_cpid; //创建共享内存进程的 id
pid_t shm_lpid; //最近操作共享内存进程的 id
shmatt_t shm_nattch; //与共享内存发生映射的进程数量
...
};

共享内存代码

//com.h
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/wait.h>
#include<unistd.h>

#define PATH "."
#define SIZE 256
int GetShm();
char* At_Shm(int shm_id);
int Delete_Shm(char* addr);
int Rm_Shm(int shm_id);

int GetShm(){
    key_t key=ftok(PATH,0);
    if(key==-1){
        perror("ftok");
        exit(1);
    }
    int flag=IPC_CREAT|0666;
    int shm_id=shmget(key,SIZE,flag);
    if(shm_id==-1){
        perror("shmget");
        exit(1);
    }
    return shm_id;
}
char* At_Shm(int shm_id){
    return (char*)shmat(shm_id,NULL,0);
}
int Delete_Shm(char* addr){
    return shmdt(addr);
}
int Rm_Shm(int shm_id){
    return shmctl(shm_id,IPC_RMID,NULL);
}
//myshm.c
#include<stdio.h>
#include<string.h>
#include"com.h"
int main()
{
    int shm_id=GetShm();
    pid_t pid=fork();
    if(pid<0){
        perror("fork");
        exit(1);
    }
    else if(pid==0){
        //child
        char* buf=At_Shm(shm_id);
        int i=0;
        while(i<60){
            buf[i]='A'+i;
            i++;
        }
        buf[59]='\0';
        Delete_Shm(buf);     //删除映射
    }
    else{
        //father
        char* buf=At_Shm(shm_id);
        sleep(2);
        printf("%s\n",buf);
        waitpid(pid,NULL,0);
        Rm_Shm(shm_id);
    }

    return 0;
}

运行结果
这里写图片描述
3.共享内存的特点
(1)共享内存是进程间通信最快的方式。
(2)共享内存没有保护机制,需要信号量控制。
(3)共享内存的基本单位是页,即大小最小是4K,且是向上取整数页的。
(4)共享内存的生命周期是随内核的。
4.systemV IPC通信特点
优点
1. 信息共享:Web服务器,通过网页浏览器使用进程间通信来共享web文件(网页等)和多媒体;
2. 加速:维基百科使用通过进程间通信进行交流的多服务器来满足用户的请求;
3. 模块化;
4. 私有权分离;
缺点
1.采用了某种形式的内核开销,降低了性能;
2.几乎大部分IPC都不是程序设计的自然扩展,往往会大大地增加程序的复杂度。

内容概要:本文档主要展示了C语言中关于字符串处理、指针操作以及动态内存分配的相关代码示例。首先介绍了如何实现键值对(“key=value”)字符串的解析,包括去除余空格和根据键获取对应值的功能,并提供了相应的测试用例。接着演示了从给定字符串中分离出奇偶位置字符的方法,并将结果分别存储到两个不同的缓冲区中。此外,还探讨了常量(const)修饰符在变量和指针中的应用规则,解释了不同类型指针的区别及其使用场景。最后,详细讲解了如何动态分配二维字符数组,并实现了对这类数组的排序与释放操作。 适合人群:具有C语言基础的程序员或计算机科学相关专业的学生,尤其是那些希望深入理解字符串处理、指针操作以及动态内存管理机制的学习者。 使用场景及目标:①掌握如何高效地解析键值对字符串并去除其中的空白字符;②学会编写能够正确处理奇偶索引字符的函数;③理解const修饰符的作用范围及其对程序逻辑的影响;④熟悉动态分配二维字符数组的技术,并能对其进行有效的排序和清理。 阅读建议:由于本资源涉及较底层概念和技术细节,建议读者先复习C语言基础知识,特别是指针和内存管理部分。在学习过程中,可以尝试动手编写类似的代码片段,以便更好地理解和掌握文中所介绍的各种技巧。同时,注意观察代码注释,它们对于理解复杂逻辑非常有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值