Linux共享存储通信
内容
- 创建共享存储区实现进程通信
机理说明
共享存储区(Share Memory)是Linux系统中通信速度最高的通信机制。该机制中共享内存空间和进程的虚地址空间满足多对多的关系。即一个共享内存空间可以映射多个进程的虚地址空间,一个进程的虚地址空间又可以连接多个共享存储区。当进程间预利用共享存储区通信时,先要在主存中建立一个共享存储区,然后将它附接到自己的虚地址空间。该机制只为进程提供了用于实现通信的共享存储区和对共享存储区进行操作的手段,然而并未提供对该区进行互斥访问及进程同步的措施。
调用函数说明
创建共享内存
shmget(key ,size ,flag)
功能:获得一个内部标识为shmid的共享存储区。
语法:int shmget = int shmget(key_t key ,int size ,int flag);
参数说明:
key 共享存储区关键字,可由用户指定。若使用IPC_PRIVATE则其值由系统产生。
size 存储区大小(字节数)。若存储区定义为字符型,则大小为定义的字符个数;若定义为整型,大小可以用sizeof(int)加以定义
flag 用户设置的标志或访问方式,如0666|IPC_CREAT,表示任意进程皆可读可写
操作允许权 | 八进制数 | 操作允许权 | 八进制数 |
---|---|---|---|
用户可读 | 0400 | 小组可写 | 0020 |
用户可写 | 0200 | 其它可读 | 0004 |
小组可读 | 0040 | 其它可写 | 0002 |
附接共享内存
字符型共享内存:
shmat(int shmid ,char *shmadddr ,int msgflg ,ulong * raddr);
数值型共享内存:
shmat(int shmid ,int *shmadddr ,int msgflg ,ulong * raddr);
语法格式:
字符型共享内存:
viraddr = (char *) shmat (shmid ,shmaddr ,shmflag);
viraddr = (int *) shmat (shmid ,shmaddr ,shmflag);
参数说明:
shmid共享存储区的描述符,可由shmget()的返回值得到。
shmaddr用户提供的共享存储区附接的虚地址。
shmflag规定存储区的操作权限。如,SHM_RND则表示操作系统在必要时舍去地址;SHM_RDONLY则表示只允许读,shmflag为0表示可读可写。
断开共享内存
shmdt(viraddr)
参数说明:
viraddr系统调用shmat()所返回的虚地址。
返回值:
函数被正确调用则返回0,错误返回-1
shmctl(int shmid ,int cmd ,struct shmid_ds * buf);
功能:对共享内存进行操作控制
参数说明:
shmid共享存储区的描述符,可由shmget()的返回值得到。
buf用户级数据结构地址,可为0。
cmd规定的操作类型
操作代码 | 含义 |
---|---|
IPC_STAT | 返回指定shmid数据结构的状态信息,放置于*buf中,必须有读取允许权 |
IPC_SET | 设置指定shmid的有效用户和操作存取权 |
IPC_RMID | 删除指定shmid以及与它相关的共享存储区的数据结构 |
SHM_LOCK | 在内存中锁定指定的共享存储区,必须是root才能执行 |
shmctl(shmid ,IPC_RMID ,0); //撤销共享内存区
实现思路
send:
- shmget()创建或者获取指定key值的共享内存
- shmat()将该内存附接到自己的虚拟地址空间
- 将消息写入共享内存
- 字符:
- 以追加方式写入,strcat(viraddr ,buffer)
- 以覆盖方式写入,strcpy(viraddr ,buffer)
- 数字:
- 直接赋值
- 操作数组\
- 字符:
- shmdt()断开共享内存
receive:
- shmget()创建或者获取指定key值的共享内存
- shmat()将该内存附接到自己的虚拟地址空间
- 输出信息
- shmdt()断开共享内存
- shmctl()撤销内存
实例
send
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
/*共享内存 share memory 实现的进程通信*/
main()
{
int shmid;
char *viraddr;
char buffer[BUFSIZ];
shmid=shmget(1234,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
while(1)
{
puts("Enter some text:");
fgets(buffer,BUFSIZ,stdin);/*从标准输入设备读入一行字符串,stdin是标准输入,C标准库里面的一 个全局变量*/
strcat(viraddr,buffer); /*字符串追加函数*/
if(strncmp(buffer,"end",3)==0)/*比较两个字符串数组*/
break;
}
shmdt(viraddr);
exit(0);
}
receive
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
main()
{
int shmid;
char *viraddr;
shmid=shmget(1234,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
printf("Your message is :\n%s",viraddr);
shmdt(viraddr); /*断开连接*/
shmctl(shmid,IPC_RMID,0); /*撤销共享内存*/
exit(0);
}
运行结果
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
/* 父进程与子进程间的通信,子进程写信息到共享内存中,父进程读取该信息
BUFSIZ为全局量定义在<stdlib.h>,8192
使用exit(0)和wait(0)进行同步*/
main()
{
int chld,shmid;
char *viraddr;
char buffer[BUFSIZ];
shmid=shmget(IPC_PRIVATE,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
while((chld=fork())==-1);
if(chld==0)
{ /*子进程块*/
while(1)
{
puts("Enter some text:"); /*写信息到共享内存*/
fgets(buffer,BUFSIZ,stdin); /*用户输入信息*/
strcat(viraddr,buffer); /*附接到进程的虚拟空间*/
if(strncmp(buffer,"end",3)==0)
break; /*输入end结束*/
}
exit(0);
}
else
{ /*父进程块*/
wait(0);
printf("Your message is:\n%s",viraddr);
shmdt(viraddr); /*断开共享内存*/
shmctl(shmid,IPC_RMID,0); /*释放共享内存*/
exit(0);
}
}
运行结果