先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题
一 what
所谓共享内存通信,实际上就是在内核空间中有一个缓存数组,用于不同用户进程间实现通信。
共享内存是一种IPC通信对象,其他IPC通信对象还有消息队列以及信号灯。其处理思想和文件IO思想是一样的,也是open、write、read、close函数,只是函数形式方式了变化,如下所示:
二 why
简单来说,共享内存也是进程间通信的实现方法之一。
三 how
3.1 创建共享内存
函数原型 : int shmget(key_t key, int size, int shmflg)函数参数 : key: IPC_PRIVATE 或 ftok的返回值IPC_PRIVATE返回的key值都是一样的,都是0size : 共享内存区大小shmflg : 同open函数的权限位,也可以用八进制表示法返回值 : 成功,共享内存段标识符 ID 文件描述符; -1 出错
3.2 demo程序示例
3.2.1 使用IPC_PRIVAT宏创建
#include
编译运行查看结果,我们发现key都是0
3.2.2 使用fotk函数创建key
ftok函数创建key值函数原型 : char ftok(const char *path, char key)参数 :path,文件路径和文件名key,一个字符返回值 :正确返回一个key值,出错返回-1
#include "stdio.h"#include "stdlib.h"#include <unistd.h>#include "sys/types.h"#include "sys/shm.h"#include "signal.h"int main(int argc, char *argv[]){int shmid;int key;key = ftok("./a.c", 'a');if (key < 0) {printf("create key failn");return -1;}printf("create key sucess key = 0x%Xn",key);shmid = shmget(key, 128, IPC_CREAT | 0777);if (shmid < 0) {printf("create shared memory failn");return -1;}printf("create shared memory sucess, shmid = %dn", shmid);system("ipcs -m");//system("ipcrm -m shmid");return 0;}
编译运行
此时的key值就不在为0了,而是0x61110105。
3.2.3 为何需要ftok先创建key值呢?
这就类似于前面无名管道和有名管道,使用IPC_PRIVATE宏创建的共享内存就类似于无名管道,只能实现有亲缘关系的进程间通信。ftok函数创建了一个key值之后,就类似于有名管道,能够实现无亲缘关系的管道间通信。
3.2.4 用户空间如何操作共享内存
因为创建的共享内存仍然属于内核空间,用户空间如何操作这片共享内存呢?
shmat函数,将共享内存映射到用户空间,方便在用户空间操作函数原型 :void *shmat(int shmid, const void *shmaddr, int shmflg)参数 :shmid ID号shmaddr 映射到啊的地址, NULL为系统自动完成的映射shmflg SHM_RDONLY共享内存只读默认是0,可读可写返回值:成功,映射后的结果;失败,返回NULL
示例代码
#include "stdio.h"#include "stdlib.h"#include <unistd.h>#include "sys/types.h"#include "sys/shm.h"#include "signal.h"int main(int argc, char *argv[]){int shmid;int key;char *p;key = ftok("./a.c", 'b');if (key < 0) {printf("create key failn");return -1;}printf("create key sucess key = 0x%Xn",key);shmid = shmget(key, 128, IPC_CREAT | 0777);if (shmid < 0) {printf("create shared memory failn");return -1;}printf("create shared memory sucess, shmid = %dn", shmid);system("ipcs -m");p = (char *)shmat(shmid, NULL, 0);if (p == NULL) {printf("shmat failn");return -1;}printf("shmat sucessn");//write share memoryfgets(p, 128, stdin);//start read share memoryprintf("share memory data:%sn", p);//start read share memory againprintf("share memory data:%sn", p);//system("ipcrm -m shmid");return 0;}
此时在console终端,通过键盘任意输入一串信息,console会打印出我们输入的信息,并且我们验证了连续2次读取同一个共享内存,发现内容都存在,这是和之前管道的区别,管道的内容读取完了之后,内容就不存在了。
3.2.5 删除用户空间的共享内存地址映射
shmdtint shmdt(const void *shmaddr)参数 ;shmat的返回值返回值 : 成功0,出错-1
#include "stdio.h"#include "stdlib.h"#include <unistd.h>#include "sys/types.h"#include "sys/shm.h"#include "signal.h"#include "string.h"int main(int argc, char *argv[]){int shmid;int key;char *p;key = ftok("./a.c", 'b');if (key < 0) {printf("create key failn");return -1;}printf("create key sucess key = 0x%Xn",key);shmid = shmget(key, 128, IPC_CREAT | 0777);if (shmid < 0) {printf("create shared memory failn");return -1;}printf("create shared memory sucess, shmid = %dn", shmid);system("ipcs -m");p = (char *)shmat(shmid, NULL, 0);if (p == NULL) {printf("shmat failn");return -1;}printf("shmat sucessn");//write share memoryfgets(p, 128, stdin);//start read share memoryprintf("share memory data:%sn", p);//start read share memory againprintf("share memory data:%sn", p);//在用户空间删除共享内存的地址shmdt(p);memcpy(p, "abcd", 4); //执行这个语句会出现segment faultreturn 0;}
编译后执行,会出现segment fault,是正确的现象
3.2.6 删除内核空间的共享内存对象
shmctlint shmctl(int shmid, int cmd, struct shmid_ds *buf)参数 ;shmid : 共享内存标识符cmd : IPC_START (获取对象属性)--- 实现了命令 ipcs -mIPC_SET (设置对象属性)IPC_RMID (删除对象属性) --- 实现了命令 ipcrm -mbuf : 指定IPC_START/IPC_SET时用以保存/设置属性返回值 : 成功0,出错-1
#include "stdio.h"#include "stdlib.h"#include <unistd.h>#include "sys/types.h"#include "sys/shm.h"#include "signal.h"#include "string.h"int main(int argc, char *argv[]){int shmid;int key;char *p;key = ftok("./a.c", 'b');if (key < 0) {printf("create key failn");return -1;}printf("create key sucess key = 0x%Xn",key);shmid = shmget(key, 128, IPC_CREAT | 0777);if (shmid < 0) {printf("create shared memory failn");return -1;}printf("create shared memory sucess, shmid = %dn", shmid);system("ipcs -m");p = (char *)shmat(shmid, NULL, 0);if (p == NULL) {printf("shmat failn");return -1;}printf("shmat sucessn");//write share memoryfgets(p, 128, stdin);//start read share memoryprintf("share memory data:%sn", p);//start read share memory againprintf("share memory data:%sn", p);//在用户空间删除共享内存的地址shmdt(p);//memcpy(p, "abcd", 4); //执行这个语句会出现segment faultshmctl(shmid, IPC_RMID, NULL); //会删除内核的共享内存对象system("ipcs -m");return 0;}