先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题
一 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值都是一样的,都是0
size : 共享内存区大小
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 memory
fgets(p, 128, stdin);
//start read share memory
printf("share memory data:%sn", p);
//start read share memory again
printf("share memory data:%sn", p);
//system("ipcrm -m shmid");
return 0;
}
此时在console终端,通过键盘任意输入一串信息,console会打印出我们输入的信息,并且我们验证了连续2次读取同一个共享内存,发现内容都存在,这是和之前管道的区别,管道的内容读取完了之后,内容就不存在了。
3.2.5 删除用户空间的共享内存地址映射
shmdt
int 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 memory
fgets(p, 128, stdin);
//start read share memory
printf("share memory data:%sn", p);
//start read share memory again
printf("share memory data:%sn", p);
//在用户空间删除共享内存的地址
shmdt(p);
memcpy(p, "abcd", 4); //执行这个语句会出现segment fault
return 0;
}
编译后执行,会出现segment fault,是正确的现象
3.2.6 删除内核空间的共享内存对象
shmctl
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
参数 ;shmid : 共享内存标识符
cmd : IPC_START (获取对象属性) --- 实现了命令 ipcs -m
IPC_SET (设置对象属性)
IPC_RMID (删除对象属性) --- 实现了命令 ipcrm -m
buf : 指定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 memory
fgets(p, 128, stdin);
//start read share memory
printf("share memory data:%sn", p);
//start read share memory again
printf("share memory data:%sn", p);
//在用户空间删除共享内存的地址
shmdt(p);
//memcpy(p, "abcd", 4); //执行这个语句会出现segment fault
shmctl(shmid, IPC_RMID, NULL); //会删除内核的共享内存对象
system("ipcs -m");
return 0;
}