一、概念
共享内存(Shared Memory)就是允许多个进程访问同一个内存空间,是在多个进程之间共享和传递数据最高效的方式。操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中,如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。
二、相关函数
1.int shmget(key_t key, size_t size, int shmflg);
功能:
用来获取或创建共享内存
参数:
key:
IPC_PRIVATE(key值会是0)
或
ftok(key值不会是0)
的返回值
size
:共享内存区大小
shmflg
:同
open
函数的权限位,也可以用
8
进制表示法
返回值:
成功:共享内存段标识符
‐‐‐ID‐‐‐
文件描述符
出错:
‐1
示例:
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int shmID;
shmID = shmget(IPC_PRIVATE,128,0777);
if(shmID == -1)
{
printf("共享内存创建失败\n");
return -1;
}
else
{
printf("共享内存创建成功,ID号%d\n",shmID);
system("ipcs -m");//查看共享内存信息
}
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/373293d1cf8d488d92fd74b451dbb49c.png)
![](https://i-blog.csdnimg.cn/direct/f46b9ee452754afeb080316c12d8313c.png)
PS:创建内存时,只会创建内核中的共享内存,并不会产生应用层的映射内存。调用映射地址函数时才会产生映射地址,这样进程之间的数据传输就不需要在内核进行操作,就可以在内核映射出来的地址进行数据传输操作。
2.void *shmat(int shm_id, const void *shm_addr, int shmflg);
功能:
把共享内存连接映射到当前进程的地址空间
参数:
shm_id:ID
号
shm_addr:
映射到的地址,
NULL
为系统自动完成的映射
shmflg:
SHM_RDONLY共享内存只读
默认是0
,表示共享内存可读写
返回值:
成功:映射后的地址
失败:
NULL
示例:
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int shmID;
key_t key;
char *p;
key = ftok("a.c",1);
if(key == -1)
printf("key fail!\n");
else
printf("key value %x\n",key);
shmID = shmget(key,128,IPC_CREAT|0777);
if(shmID == -1)
{
printf("共享内存创建失败\n");
return -1;
}
else
{
printf("共享内存创建成功,ID号%d\n",shmID);
system("ipcs -m");//查看共享内存信息
}
p = (char *)shmat(shmID, NULL, 0);
printf("映射的地址是%p",p);
printf("请输入数据:");
fgets(p,128,stdin);
printf("共享内存的数据是%s\n",p);
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/d0b0d44dadcd4b669e9758f4b95b1e0f.png)
3.int shmdt(const void *shmaddr);
功能:
将进程里的地址映射删除
参数:
shmid
:要操作的共享内存标识符
返回值:
成功:
0
出错:
‐1
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int shmID;
key_t key;
char *p;
key = ftok("a.c",1);
if(key == -1)
printf("key fail!\n");
else
printf("key value %x\n",key);
shmID = shmget(key,128,IPC_CREAT|0777);
if(shmID == -1)
{
printf("共享内存创建失败\n");
return -1;
}
else
{
printf("共享内存创建成功,ID号%d\n",shmID);
system("ipcs -m");//查看共享内存信息
}
p = (char *)shmat(shmID, NULL, 0);
printf("映射的地址是%p",p);
printf("请输入数据:");
fgets(p,128,stdin);
printf("共享内存的数据是%s\n",p);
int add = shmdt(p);//删除映射内存
if(add == 0)
printf("删除映射内存成功\n");
p = 0;
printf("删除共享内存过后的地址%p\n",p);
return 0;
}
![](https://i-blog.csdnimg.cn/direct/5544ec3896504ca7886481bd054a4239.png)
4.int shmctl(int shm_id, int command, struct shmid_ds *buf);
功能:
删除共享内存对象
参数:
shmid
:要操作的共享内存标识符
cmd :
IPC_STAT (获取对象属性
)‐‐‐
实现了命令
ipcs ‐m
IPC_SET (设置对象属性
)
IPC_RMID (删除对象
) ‐‐‐
实现了命令
ipcrm ‐m
buf
:指定
IPC_STAT/IPC_SET
时用以保存
/
设置属性
返回值:
成功:
0
出错:
‐1
示例:
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int shmID;
key_t key;
char *p;
key = ftok("a.c",1);
if(key == -1)
printf("key fail!\n");
else
printf("key value %x\n",key);
shmID = shmget(key,128,IPC_CREAT|0777);
if(shmID == -1)
{
printf("共享内存创建失败\n");
return -1;
}
else
{
printf("共享内存创建成功,ID号%d\n",shmID);
system("ipcs -m");//查看共享内存信息
}
p = (char *)shmat(shmID, NULL, 0);
printf("映射的地址是%p",p);
printf("请输入数据:");
fgets(p,128,stdin);
printf("共享内存的数据是%s\n",p);
int add = shmdt(p);//删除映射内存
if(add == 0)
printf("删除映射内存成功\n");
p = 0;
printf("删除共享内存过后的地址%p\n",p);
shmctl(shmID,IPC_RMID,NULL);//删除共享内存对象
system("ipcs -m");
return 0;
}
运行结果:
![](https://i-blog.csdnimg.cn/direct/0816febd2d4f4611948df4bd92abe76a.png)
进程间的通信示例:
shm_write.c:
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int shmID;
key_t key;
char *p;
key = ftok("a.c",1);
if(key == -1)
printf("key fail!\n");
else
printf("key value %x\n",key);
shmID = shmget(key,128,IPC_CREAT|0777);
if(shmID == -1)
{
printf("共享内存创建失败\n");
return -1;
}
else
{
printf("共享内存创建成功,ID号%d\n",shmID);
system("ipcs -m");//查看共享内存信息
}
p = (char *)shmat(shmID, NULL, 0);
printf("映射的地址是%p",p);
printf("请输入数据:");
fgets(p,128,stdin);
system("ipcs -m");
return 0;
}
shm_read.c:
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int shmID;
key_t key;
char *p;
key = ftok("a.c",1);
if(key == -1)
printf("key fail!\n");
else
printf("key value %x\n",key);
shmID = shmget(key,128,0777);
if(shmID == -1)
{
printf("共享内存创建失败\n");
return -1;
}
else
{
printf("共享内存创建成功,ID号%d\n",shmID);
system("ipcs -m");//查看共享内存信息
}
p = (char *)shmat(shmID, NULL, 0);
printf("映射的地址是%p\n",p);
printf("共享内存的数据是%s\n",p);
int add = shmdt(p);//删除映射内存
if(add == 0)
printf("删除映射内存成功\n");
p = 0;
printf("删除共享内存过后的地址%p\n",p);
shmctl(shmID,IPC_RMID,NULL);//删除共享内存对象
system("ipcs -m");
return 0;
}
~
三、特点
1.
共享内存创建之后,一直存在于内核中,
直到被删除或系统关闭
2.
共享内存和管道不一样,读取后,
内容仍然在共享内存中