进程间通信IPC---共享内存

本文介绍Linux下的内存映射(mmap)机制及其在进程间通信中的应用,包括POSIX和System V共享内存的区别与实现细节。

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

1.整体思维导图
这里写图片描述

2.详细介绍
2.1 POSIX内存映射文件
原理
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改,mmap()系统调用使得进程之间可以通过映射一个普通的文件实现共享内存。普通文件映射到进程地址空间后,进程可以向访问内存的方式对文件进行访问,不需要其他系统调用(read,write)去操作。如果需要同步到文件里,需要调用msync().
特点:访问速度慢,因为内核为同步或异步更新到文件系统中,而内存区对象是直接操作内存的。存储量大。
生命周期:随文件,即进程重启或内核自举不后丢失,除非显示rm掉文件后丢失。

2.1.1 接口函数详解
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

  • addr: 指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。
  • length: 代表将文件中多大的部分映射到内存。
  • prot : 映射区域的保护方式。可以为以下几种方式的组合:
    PROT_EXEC 映射区域可被执行
    PROT_READ 映射区域可被读取
    PROT_WRITE 映射区域可被写入
    PROT_NONE 映射区域不能存取
  • flags : 影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARE或 MAP_PRIVATE。
    MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
    MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。
    MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
    MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。
    MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
    MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。
  • fd : 要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,
    然后对该文件进行映射,可以同样达到匿名内存映射的效果。
  • offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是PAGE_SIZE的整数倍。
  • 返回值:
    若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。
    错误代码:
    EBADF 参数fd 不是有效的文件描述词
    EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。
    EINVAL 参数start、length 或offset有一个不合法。
    EAGAIN 文件被锁住,或是有太多内存被锁住。
    ENOMEM 内存不足。

int munmap( void * addr, size_t len ) ;

  • 函数说明 munmap()用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。当进程结束或利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述符时不会解除映射。

  • 返回值 如果解除映射成功则返回0,否则返回-1,错误原因存于errno中错误代码EINVAL

int msync ( void * addr , size_t len, int flags) ;

  • 注释:
    1、刷新变化函数msync()
    2、进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作。可以通过调用msync()函数来实现磁盘文件内容与共享内存区中的内容一致,即同步操作.

  • 说明:
    1 . 当映射区数据被修改时,内核会稍后将其更新到文件。但有时候为了确保修改能被反映到文件,可以调用 msync 函数来进行同步操作。
    2 . addr:文件映射到进程空间的地址;
    len:映射空间的大小。
    3 . 参数 flags 控制回写到文件的具体方式。MS_ASYNC 、MS_SYNC 必须指定其一。
    MS_ASYNC ,只是将写操作排队,并不等待写操作完成就返回。
    MS_SYNC ,等待写操作完成后才返回。
    MS_INVALIDATE ,作废与实际文件内容不一致缓存页,有的实现则是作废整个映射区的缓存页。后续的引用将从文件获取数据。

    4 . 返回值:成功则返回0;失败则返回-1;

2.2 POSIX共享内存对象
原理
在 /dev/shm (tmpfs的文件系统)下,创建一段共享内存,然后映射到各自的进程里。
特点:访问速度快。
生命周期:随内核,即进程重启共享内存中数据不会丢失;但是内核自举或显示调用shm_unlink或rm掉文件删除后丢失。
2.2.1 接口函数详解
int shm_open(const char *name,int oflag,mode_t mode);

  • 功能:打开或创建一个共享内存区

  • 参数:name 共享内存区的名字
    cflag 标志位
    mode 权限位
    返回值:
    成功返回0,出错返回-1

  • 注意项:
    oflag参数必须含有O_RDONLY和O_RDWR标志,还可以指定如下标志:O_CREAT,O_EXCL或O_TRUNC.
    mode参数指定权限位,它指定O_CREAT标志的前提下使用。
    shm_open的返回值是一个整数描述字,它随后用作mmap的第五个参数。

int ftruncate(int fd, off_t length);

  • 功能:改变文件大小 。
  • 参数:fd:为已打开的文件描述符。
    length:设置的大小。

  • 注意项:必须是以写入模式打开的文件。如果原来的文件件大小比参数length大,则超过的部分会被删去。

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
同上

int shm_unlink(const char *name);

  • 功能:删除一个共享内存区

  • 参数:name:共享内存区的名字

注意项:–

2.3 SYSTEM V共享内存对象
原理:同POSIX共享内存对象

2.3.1 接口函数详解
key_t ftok( char * fname, int id );

  • 功能:系统建立IPC通讯(消息队列、信号量和共享内存)时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。
  • 参数:fname:指定的文件名(已经存在的文件名)。
    id:子序号。
  • 返回值:当成功执行的时候,一个key_t值将会被返回,否则 -1 被返回。

int shmget(key_t key, size_t size, int shmflg);

  • 功能:得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符。
  • 参数:
    key:0(IPC_PRIVATE):会建立新共享内存对象;大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值。
    size:大于0的整数:新建的共享内存大小,以字节为单位;0:只获取共享内存时指定为0。
    shmflg:0:取共享内存标识符,若不存在则函数会报错。IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符;IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个消息队列;如果存在这样的共享内存则报错。
  • 返回值:成功:返回共享内存的标识符。失败:-1,错误原因存于error中。

void *shmat(int shmid, constvoid shmaddr,int shmflg);

  • 功能:连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。
  • 参数:
    msqid:共享内存标识符。
    shmaddr:指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置。
    shmflg:SHM_RDONLY:为只读模式,其他为读写模式。
  • 返回值:成功:附加好的共享内存地址;出错:-1,错误原因存于error中。

void shmdt(constvoid shmaddr);

  • 功能:与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存。
  • 参数:shmaddr:连接的共享内存的起始地址。
  • 返回值:成功:0;出错:-1,错误原因存于error中。

int shmctl(int shmid, int cmd, struct shmid_ds* buf);

  • 功能:完成对共享内存的控制。
  • 参数:msqid:共享内存标识符。
    cmd:IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中;
    IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内;IPC_RMID:删除这片共享内存。
    buf:共享内存管理结构体。具体说明参见共享内存内核结构定义部分。
  • 返回值:成功:0;出错:-1,错误原因存于error中。

3.应用实例

内容概要:本文深入探讨了Kotlin语言在函数式编程和跨平台开发方面的特性和优势,结合详细的代码案例,展示了Kotlin的核心技巧和应用场景。文章首先介绍了高阶函数和Lambda表达式的使用,解释了它们如何简化集合操作和回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建和平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发和Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程和跨平台开发领域不断完善和发展。; 适合人群:对函数式编程和跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者和中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数和Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解和实践Kotlin的函数式编程特性和跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解和掌握。
内容概要:本文深入探讨了利用历史速度命令(HVC)增强仿射编队机动控制性能的方法。论文提出了HVC在仿射编队控制中的潜在价值,通过全面评估HVC对系统的影响,提出了易于测试的稳定性条件,并给出了延迟参数与跟踪误差关系的显式不等式。研究为两轮差动机器人(TWDRs)群提供了系统的协调编队机动控制方案,并通过9台TWDRs的仿真和实验验证了稳定性和综合性能改进。此外,文中还提供了详细的Python代码实现,涵盖仿射编队控制类、HVC增强、稳定性条件检查以及仿真实验。代码不仅实现了论文的核心思想,还扩展了邻居历史信息利用、动态拓扑优化和自适应控制等性能提升策略,更全面地反映了群体智能协作和性能优化思想。 适用人群:具备一定编程基础,对群体智能、机器人编队控制、时滞系统稳定性分析感兴趣的科研人员和工程师。 使用场景及目标:①理解HVC在仿射编队控制中的应用及其对系统性能的提升;②掌握仿射编队控制的具体实现方法,包括控制器设计、稳定性分析和仿真实验;③学习如何通过引入历史信息(如HVC)来优化群体智能系统的性能;④探索中性型时滞系统的稳定性条件及其在实际系统中的应用。 其他说明:此资源不仅提供了理论分析,还包括完整的Python代码实现,帮助读者从理论到实践全面掌握仿射编队控制技术。代码结构清晰,涵盖了从初始化配置、控制律设计到性能评估的各个环节,并提供了丰富的可视化工具,便于理解和分析系统性能。通过阅读和实践,读者可以深入了解HVC增强仿射编队控制的工作原理及其实际应用效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值