文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Linux进程间通信怎么实现

2023-07-05 15:49

关注

这篇文章主要讲解了“Linux进程间通信怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Linux进程间通信怎么实现”吧!

共享内存

好处: 效率高,进程可以直接读写内存,而不需要复制任何数据,而管道、消息队列等通信方式,则需要在内核和用户空间进行四次数据复制。

并且只有在解除映射时,共享内存的内容才会写会文纪念

共享内存通过内核对象,使得不同的进程在自己的虚拟地址空间上分配一块空间映射到相同的物理内存空间上,这块物理内存空间对于映射到上面的每个进程而言都是可以访问的。(临界资源)

Linux进程间通信怎么实现

共享内存就是允许两个不相关的进程访问同一个逻辑内存

共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。

不同进程之间共享的内存通常安排为同一段物理内存。

进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc()分配的内存一样。

而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以 访问同一段共享内存的任何其他进程。

mmap()及其相关的系统调用

mmap是linux操作系统提供给用户空间调用的内存映射函数,很多人仅仅只是知道可以通过mmap完成进程间的内存共享和减少用户态到内核态的数据拷贝次数,但是并没有深入理解mmap在操作系统内部是如何实现的,原理是什么

Linux进程间通信怎么实现

mmap()系统调用使得进程之间可以通过映射同一个普通文件实现内存共享。普通文件被映射到进程地址空间后,进程可以访问普通内存一样对文件进行访问,不必再调用read和write操作。 

注意: mmap并不是完全为了IPC而设计的,只是IPC的一种应用方式,它本身提供了一种像访问普通内存一样的访问对普通文件进行操作的方式。

通过使用带有特殊权限集的虚拟内存段来实现。对这类虚拟内存段的读写会使操作系统去读写磁盘文件中与之对应的部分。

mmap 函数创建一个指向一段内存区域的指针,该内存区域与可以通过一个打开的文件描述符访问的文件的内容相关联

解释如下:

mmap()

#include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

可以通过传递 offset 参数来改变经共享内存段访问的文件中数据的起始偏移值。

打开的文件描述符由 fd 参数给出。

可以访问的数据量(即内存段的长度)由 length 参数设置。

可以通过 addr 参数来请求使用某个特定的内存地址。如果它的取值是零,结果指针就将自动分配。这是推荐的做法,否则会降低程序的可移植性,因为不同系统上的可用地址范围是不一样的。

prot 参数用于设置内存段的访问权限。它是下列常数值的按位或的结果

flags 参数控制程序对该内存段的改变所造成的影响:

Linux进程间通信怎么实现

mmap()用于共享内存的量和两种方式如下:

使用普通文件提供的内存映射,适用于任何进程间,使用该方式需要先打开或者创建一个文件,再调用ngmmap,典型调用代码如下:

fd = open(name.falg.mode);if(fd < 0)ptr = mmap(NULL,len.PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

使用特殊文件提供的内存映射,适用于具有亲缘关系的进程之间,由于父子进程特殊的亲缘关系,在父进程中先调用mmap,调用fork,那么在代用fork之后,子进程可以继承父进程匿名映射后的地址空间,同样也继承mmap返回的地址,这样父子进程就可以通过映射区域进行通信了。(注意:一般来说,子进程单独维护从父进程继承而来的一些变量,而mmap()返回的地址由父子进程共同维护)【具体使用实现敬请期待博主整理】

munmap()

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

#include <sys/mman.h>int munmap(void *addr, size_t length);

共享内存的使用

与信号量一样,在Linux中也提供了一组函数接口用于使用共享内存,而且使用共享共存的接口还与信号量的非常相似,而且比使用信号量的接口来得简单。它们声明在头文件 sys/shm.h 中。 

1.获取或创建内核对象,并且制定共享内存的大小(系统分配物理空间是,按照页进行分配)

int shmget(key_t key, int size, int flag);

只是创建内核对象,并申请物理空间

返回值

2.分配自己虚拟地址空间映射到共享内存的物理空间上

void *shmat(int shmid,const void *addr, int flag);

调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败返回-1.

3.断开当前进程与共享内存的映射

不使用删除而使用断开的原因是因为:也许还存在其他的进程会继续使用这块共享内存

int shmdt(const void *addr);

4.操作共享内存的方法

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

IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。

IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值

IPC_RMID:删除共享内存段

因为有连接计数器,除非最后一个进程与该共享段断开连接,则删除该共享段。否则,并不会真正删除该共享段,但是共享内存的内核对象会被立即删除,不能使用shmat方法与该段连接。 

一个进程调用该方法删除后,不会影响之前已经和该共享存储段连接的进程

下面我们利用共享内存来进行一个简单的测试:

Linux进程间通信怎么实现

Linux进程间通信怎么实现

完成下面的过程,

Linux进程间通信怎么实现

成功在共享内存中读到了数据

Linux进程间通信怎么实现

#include<stdio.h>#include<stdlib.h>#include<assert.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#include"sem.h"#define READSEM 1#define WRITESEM 0int main(){int shmid = shmget((key_t)1234,128,0664 | IPC_CREAT);assert(shmid != -1);char *ptr = (char*)shmat(shmid,NULL,0);assert(ptr != (char*)-1);int initVal[] = {1,0};int semid = SemGet(1234,intVal,2);assert(semid != -1);//A进程写while(1){SemP(semid,WRITESEM);printf("Input:");fgets(ptr,127,stdin);SemV(semid,READSEM);if(strncmp(ptr,"end",3) == 0){break;}}shmdt(ptr);exit(0);}
#include<stdio.h>#include<stdlib.h>#include<assert.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#include"sem.h"#define READSEM 1#define WRITESEM 0int main(){int shmid = shmget((key_t)1234,128,0664 | IPC_CREAT);assert(shmid != -1);char *ptr = (char*)shmat(shmid,NULL,0);assert(ptr != (char*)-1);int initVal[] = {1,0};int semid = SemGet(1234,intVal,2);assert(semid != -1);//B进程读while(1){SemP(semid,READSEM);if(strncmp(ptr,"end",3) == 0){break;}int i = 0;for(;i < strlen(ptr) - 1;i++){printf("%c",toupper(ptr[i]));fflush(stdout);sleep(1);}printf("\n");SemV(semid,WRITESEM);}shmdt(ptr);exit(0);}

从上面的代码中我们可以看出: 

共享内存是最快的IPC,在通信过程中少了两次数据的拷贝。(相较于管道)

命令管理共享内存

感谢各位的阅读,以上就是“Linux进程间通信怎么实现”的内容了,经过本文的学习后,相信大家对Linux进程间通信怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-人工智能
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯