300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 【Linux】进程间通信(共享内存)

【Linux】进程间通信(共享内存)

时间:2021-01-24 02:23:34

相关推荐

【Linux】进程间通信(共享内存)

共享内存

1、实现原理:

共享内存区域说白了就是多个进程共享的一块物理内存地址,只是将这块物理内存分别映射到自己的虚拟空间地址上。

假设有 10 个进程将这块区域映射到自己的虚拟地址上,那么,这 10 个进程间就可以相互通信。

由于是同一块区域在10 个进程的虚拟地址上,当第一个进程向这块共享内存的虚拟地址中写入数据时,

其他 9 个进程也都会看到。

因此共享内存是进程间通信的一种最快的方式。但是进程之间使用这块共享空间时,必须做同步控制。

进程的地址空间都是独立,受保护的!共享内存通信方式是最快的IPC,因为不需要数据的copy,所以效率较高

2、特点

因为多个进程操作同一块物理内存,所以进程必须同步执行因为进程直接通过虚拟地址操作物理内存,所以不需要拷贝数据,共享内存是最快的一种进程间通讯方式共享内存的生命周期随进程,也需要显示地删除。共享内存没有互斥与同步机制,因此,我们在使用时,需要自己添加。

3、相关函数

(1)用于创建或获取共享内存

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

shmget():用于创建或获取共享内存,key:不同的进程使用相同的key值可以获取到同一个共享内存Size:创建共享内存时,指定要申请的共享内存空间大小flag:IPC_CREAT IPC_EXCL,单独使用IPC_CREAT,如果消息队列不存在则创建之,如果存在则打开返回;单独使用IPC_EXCL是没有意义的;两个同时使用,如果消息队列不存在则创建之,如果存在则出错返回。返回值:成功返回共享内存的ID,失败返回-1

(2)连接到进程的虚拟地址空间(启用对第一个创建的共享内存的访问)

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

shmid:共享内存的标识码shmat():将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上shmaddr:一般给NULL,由系统自动选择映射的虚拟地址空间shmflg:一般给0,可以给SHM_RDONLY为只读模式,其他的为读写返回值:成功返回(一个虚拟地址,此虚拟地址就是映射到)共享内存的首地址,失败返回NULL

(3)断开连接

int shmdt(const void *shmaddr);

shmdt():断开当前进程的shmaddr指向的共享内存映射返回值: 成功返回0,失败返回-1;

(4)删除共享内存

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

shmctl():控制共享内存,cmd:IPC_RMID删除共享内存段,并不会立即删除共享空间,返回值:成功返回0,失败返回-1

不能使用shmat方法与共享存储段建立映射关系

//注:内核中做映射时,空间都是以4K作为大小的,

(以页面进行大小分配的-----》页面映射)

命令:ipcs -m 查看 和 ipcrm -m删除

4、代码模拟

示例:进程a从键盘循环获取数据并拷贝到共享内存中,进程b从共享内存中读取并打印数据,要求进程a输入一次,进程b输出一次。进程a不输入,进程b也不输出。

shmA.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <assert.h>#include <sys/shm.h>#include "sem.h"int main(){int shmid = shmget((key_t)1234,128,IPC_CREAT | 0664);assert(shmid != -1);char *ptr = (char *)shmat(shmid,NULL,0);assert(ptr != (char*)-1);//0:sem1 1:sem2int init_val[2] = {0, 1};int semid = CreateSem(1234, init_val,2);assert(semid != -1);while(1){SemP(semid,1); //B--->A 此处的1为下标printf("input: ");fgets(ptr, 127, stdin);SemV(semid,0); //A---->Bif(strncmp(ptr,"end",3) == 0){break;}shmdt(ptr);shmctl(shmid,IPC_RMID,NULL);}}

shmB.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <assert.h>#include <sys/shm.h>#include "sem.h"#include <time.h>int main(){srand((unsigned int)(time(NULL)*time(NULL)));int shmid = shmget((key_t)1234,128,IPC_CREAT | 0664);assert(shmid != -1);char *ptr = (char *)shmat(shmid,NULL,0);assert(ptr != (char*)-1);int init_val[2] = {0, 1};int semid = CreateSem(1234, init_val,2);assert(semid != -1);while(1){SemP(semid,0); //A---->Bif(strncmp(ptr,"end",3)==0){break;}printf("B process: %s",ptr);int n = rand() % 3+1;sleep(n);printf("B Deal Over\n");memset(ptr, 0, 128);SemV(semid,1); //B--->A}shmdt(ptr);shmctl(shmid,IPC_RMID,NULL);DeleteSem(semid);}

5、进程间通信小结

(1)进程间通信IPC:进程之间都是相互独立的,任何一个进程的全局变量在另一个进程中是看不到的,如果进程之间需要交换数据就要通过内核。进程间通信(InterProcess Communication)的本质就是让两个进程看到共同的资源。

(2)进程间通信的目的:

数据传输:一个进程需要将它的数据发送给另一个进程资源共享:多个进程之间共享同样的资源通知事件:一个进程需要向另一个进程发送消息,通知其发生了某种事情(比如进程终止父进程告诉子进程)进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,能够及时知道它的状态改变。

(3)类别:

有名管道:通过文件描述符的方式做进程间通信,有阻塞非阻塞机制在其中,效率低无名管道:父子进程间的通讯消息队列:进程可以根据消息类型获取不同的消息---->有个中间件MQ信号量:做同步控制的,对临界资源临界区的访问或两个进程的同步,协作关系做同步控制共享内存:最快的IPC

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。