linux共享内存

it2025-11-10  6

四:IPC通信 IPC通信(Inter-Process Communication) 三种: 共享内存、消息队列、信号灯 这个IPC对象,肯定是存在于内核中。而且用户空间的文件系统中有没有IPC的文件类型?没有。 有名管道为什么能实现无亲缘关系的进程之间的通信? 是因为用户空间有管道这种文件类型。 IPC是不是只能用于亲缘关系进程之间的通信呢?肯定不是

它是怎样实现无亲缘关系之间的通信呢?也即你是保证用户空间的二个进程对内核中的同一个IPC对象的操作。(ftok)

IPC对象的打开或创建: 类似于open的函数呢? 打开或创建一个共享内存对象,共享内核在内核是什么样子的? 一块缓存,变类似于用户空间的数组或malloc函数分配的空间一样

查看IPC对象 ipcs –m -q -s 删除IPC对象 ipcrm -m id 返回值:共享内存段标识符 IPC的ID号 最后的命令iprcm -m shmid没有运行

(2) ftok:创建key值。

key_t ftok(const char *path, char key ) 参数:第一个参数:文件路径和文件名; 第二个参数:一个字符。 返回值:正确返回一个key值,出错返回-1

IPC_PRIVATE操作时,共享内存的key值都一样,都是0,所以使用ftok来创建key值。只要key值是一样的,用户空间的进程通过这个函数打开,则会对内核的同一个IPC对象操作。 注意,这里的这个文件要纯在,如果不存在则创建不成功,如果没有则在外面创建一个a.c文件再运行 在这里通过宏 IPC_PRIVATE操作时,就像无名管道一样对有亲缘关系的进程之间通信操作,而ftok则时操作有名管道,对无亲缘关系的通信也能操作

(3) shmat 将共享内存映射到用户空间的地址中 能不能用read ,write呢? 为了方便用户空间对共享内存的操作,使用地址映射的方式。

void *shmat (int shmid, const void *shmaddr, int shmflg); //类似malloc 参数:第一个参数:ID号; 第二个参数:映射到的地址,NULL为系统自动完成的映射; 第三个参数shmflg: SHM_RDONLY共享内存只读 默认是0,表示共享内存可读写。 返回值:成功:映射后的地址; 失败:NULL。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190804003847344.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NTRE5kZXNhc2Rm,size_16,color_FFFFFF,t_70)

对于无名管道,读完之后内容就没有了,但是对于shmat来说,读完之后的内容还是存在的,对内容进行第二次读取,如下图 共享内存特点: 1、共享内存创建之后,一直存在于内核中,直到被删除或系统关闭; 2、共享内存和管道不一样,读取后,内容仍在其共享内存中。

(4) shmdt:将进程里的地址映射删除。

int shmdt(const void *shmaddr); 参数:shmaddr共享内存映射后的地址 返回值:成功:0 出错:-1

(5) shmctl:删除共享内存对象。 函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf); 函数参数:shmid:要操作的共享内存标识符。 cmd : IPC_STAT (获取对象属性)— 实现了命令ipcs -m IPC_SET (设置对象属性) IPC_RMID (删除对象) —实现了命令ipcrm -m buf :指定IPC_STAT/IPC_SET时用以保存/设置属性。 函数返回值:成功:0 出错:-1 在这里可以看到,读完hello linux之后内存就释放了没有了。

有亲缘关系进程之间的通信的实例:

怎样通过共享内存实现有亲缘关系进程之间的通信框架 父进程不断写入共享内存,子进程不断读取共享内存的内容(单向通信)当使用IPC_PRIVATE 实现有亲缘关系进程之间通信时,fork()函数一定要放在shmget()函数之后 结果如下图 父进程不断的写,子进程不断的读,不断循环

第二题 这里实现的功能是服务端不断的写,客户端不断的读取 服务器端的代码

#include<signal.h> #include<unistd.h> #include<sys/types.h> #include<stdlib.h> #include<sys/ipc.h> #include<stdio.h> struct mybuf { int pid; char buf[124]; }; void myfun(int signum) { return; } int main() { int shmid; int key; struct mybuf *p; int pid; key = ftok("./a.c",'a'); if(key < 0) { printf("creat key failure\n"); return -1; } printf("creat key sucess\n"); shmid = shmget(key,128,IPC_CREAT | 0777); if(shmid < 0) { printf("creat share memory failure\n"); return -1; } printf("creat share memory sucess shmid = %d\n",shmid); signal(SIGUSR2,myfun); p = (struct mybuf *)shmat(shmid,NULL,0);//地址映射 if(p == NULL) { printf("parent shmat function failure\n"); return -3; } //开始读写前获得pid p->pid= getpid();//写入服务器端的pid pause();//等待客户端的pid读 pid =p->pid;//读完后接受客户端的pid //开始读写 while(1) { printf("parent process start write share memory:\n"); fgets(p->buf,128,stdin); kill(pid,SIGUSR1);//客户端读数据 pause();//等待客户端读 } shmdt(p); shmctl(shmid,IPC_RMID,NULL); system("ipcs -m"); return 0; }

客户端的代码

#include<stdio.h> #include<sys/shm.h> #include<signal.h> #include<unistd.h> #include<sys/types.h> #include<stdlib.h> #include<sys/ipc.h> struct mybuf { int pid; char buf[124]; }; void myfun(int signum) { return; } int main() { int shmid; int key; struct mybuf *p; int pid; key = ftok("./a.c",'a'); if(key < 0) { printf("creat key failure\n"); return -1; } printf("creat key sucess\n"); shmid = shmget(key,128,IPC_CREAT | 0777); if(shmid < 0) { printf("creat share memory failure\n"); return -1; } printf("creat share memory sucess shmid = %d\n",shmid); signal(SIGUSR1,myfun);//地址映射 p = (struct mybuf *)shmat(shmid,NULL,0);//地址映射 if(p == NULL) { printf("parent shmat function failure\n"); return -3; } //开始读写前获得pid,客户端先获得pid //读共享内存 pid = p->pid; //写客户端pid到共享内存中 p->pid = getpid(); //告诉服务端已经写好了 kill(pid,SIGUSR2); //客户端开始读写 while(1) { pause();//等待服务器端写入数据 printf("cilent process recerver datat from share memory:%s",p->buf); kill(pid,SIGUSR2);//告诉服务器端可以写共享内存 } shmdt(p); shmctl(shmid,IPC_RMID,NULL); system("ipcs -m"); return 0; }
最新回复(0)