文章目录
一、使用流程
共享存储允许两个或多个进程共享一个给定的存储区,是进程间通信最快的一种方式。
不要同时对共享存储空间进行写操作,通常,信号量用于同步共享存储访问。
最简单的共享内存的使用流程
①ftok函数生成键值
②shmget函数创建共享内存空间
③shmat函数获取第一个可用共享内存空间的地址
④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存和结构)
⑤shmctl函数进行删除共享存储空间
使用步骤
1.ftok函数生成键值
每一个共享存储段都有一个对应的键值(key)相关联(消息队列、信号量也同样需要)。
所需头文件:#include<sys/ipc.h>
函数原型 :key_t ftok(const char *path ,int id);
path为一个已存在的路径名
id为0~255之间的一个数值,代表项目ID,自己取
返回值:成功返回键值(相当于32位的int)。出错返回-1
例如:key_t key = ftok( “/tmp”, 66);
2.shmget函数创建共享存储空间并返回一个共享存储标识符
所需头文件:#include<sys/shm.h>
函数原型: int shmget(key_t key, size_t size,int flag);
key为ftok生成的键值
size为共享内存的长度,以字节为单位
flag为所需要的操作和权限,可以用来创建一个共享存储空间并返回一个标识符或者获得一个共享标识符。
flag的值为IPC_CREAT:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则直接返回共享存储标识符。
flag的值为 IPC_CREAT | IPC_EXCL:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则产生错误。
返回值:成功返回共享存储ID;出错返回-1
例如:int id = shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个整形共享存储标识符,如果key值已经存在有共享存储空间了,则出错返回-1。
int id = shmget(key,4096,IPC_CREAT|0666);创建一个大小为4096个字节的权限为0666(所有用户可读可写,具体查询linux权限相关内容)的共享存储空间,并返回一个共享存储标识符,如果key值已经存在有共享存储空间了,则直接返回一个共享存储标识符。
3.shmat函数获取第一个可用共享内存空间的地址
所需头文件:#include<sys/shm.h>
函数原型: void *shmat(int shmid, const void *addr, int flag);
shmid为shmget生成的共享存储标识符
addr指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
flag为对数据的操作,如果指定为SHM_RDONLY则以只读方式连接此段,其他值为读写方式连接此段。
翻阅linux下shm.c文件得到#define SHM_RDONLY 010000 /* read-only access */
返回值:成功返回指向共享存储段的指针;错误返回-1(打印出指针的值为全F)
例如:char *addr = shmat(id, NULL, 0);就会返回第一个可用的共享内存地址的指针的值给addr
4.shmdt函数进行分离
当不需要对此共享内存进行操作时候,调用shmdt函数进行分离,不是删除此共享存储空间哟。
所需头文件:#include<sys/shm.h>
函数原型: int shmdt(const void *addr);
addr为shmat函数返回的地址指针
返回值:成功返回0;错误返回-1
例如:int ret = shmdt(addr);
5.shmctl函数对共享内存进行控制
简单的操作就是删除共享存储空间了,也可以获取和改变共享内存的状态
所需头文件:#include<sys/shm.h>
函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid就是shmget函数返回的共享存储标识符
cmd有三个,常用删除共享内存的为IPC_RMID;IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中;IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内。(内核为每个共享存储段维护着一个结构,结构名为shmid_ds,这里就不讲啦,里面存放着共享内存的大小,pid,存放时间等一些参数)
buf就是结构体shmid_ds
返回值:成功返回0;错误返回-1
例如:int ret = shmctl(id, IPC_RMID,NULL);删除id号的共享存储空间
编程验证
shmw.c
创建共享内存,写入共享内存。 这边写我自己很帅
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#include<strsep.h>
int main ()
{
char *shmaddr;
key_t key;
// key_t ftok(const char *path ,int id);
key = ftok("./",24);
int shmgetId;
shmgetId = shmget(key,1024*4,IPC_CREAT|0666);
if (shmgetId == -1)
{
printf("shmget fail! \n");
exit(-1);
}
printf("shmget success !\n");
//函数原型: void *shmat(int shmid, const void *addr, int flag);
shmaddr = shmat(shmgetId,0,0);
printf("shmat success!");
strcpy(shmaddr," tea eggs hansome !");
printf("write sucee\n");
sleep(5);
//函数原型: int shmdt(const void *addr);
shmdt(shmaddr);
//int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl(shmgetId,IPC_RMID,0);
return 0;
}
shmr.c
读取共享内存的值
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#include<strsep.h>
int main ()
{
char *shmaddr;
// 所需头文件:#include<sys/ipc.h>
key_t key;
// key_t ftok(const char *path ,int id);
key = ftok("./",24);
int shmgetId;
shmgetId = shmget(key,1024*4,0);
if (shmgetId == -1)
{
printf("shmget fail! \n");
exit(-1);
}
printf("shmget success !\n");
//函数原型: void *shmat(int shmid, const void *addr, int flag);
shmaddr = shmat(shmgetId,0,0);
printf("shmat success!");
printf("data: %s\n",shmaddr);
//函数原型: int shmdt(const void *addr);
shmdt(shmaddr);
//int shmctl(int shmid, int cmd, struct shmid_ds *buf);
return 0;
}
运行结果
查看IPC
ipcs -m
删除IPC
ipcs -m + id