Unix-IPC之共享内存
一,共享内存的概念
共享内存通信技术是一种最快的可用IPC形式,它是针对其他通信机制运行效率低和设计的新型通信技术(其他的如:信号量,管道,套接字等)。这种通信技术往往与其他通信机制(如信号量)结合使用,用于达到进程间的同步及互斥。
原理:
这种方式是在所有进程的独立空间之外开辟一块内存空间,它不属于任何一个进程,当所有进程都可以访问。利用这样的共享特性,发送进程就可以往共享区域中写入数据,而接收进程则可以从共享区域中获取所需信息。
采用共享内存的进程通信的特点:
- 进程通信中,需要交互的数据或消息不发生存储移动。
- 当需要交互时,通信进程双方通过共享内存区域完成信息交互。
- 对于共享内存区,可以用虚拟映射方式将其作为交互进程的内存使用。
二,相关系统调用
共享内存区的建立
Unix中通系统调用shmget()
来建立一块共享内存,函数定义:
int shmget(key_t key, int size, int flag);
参数说明:
- key:表示共享内存的标识符
- size:共享内存以字节为单位的最小值,如果创建的是一个新共享区必须指定size,若使用已有的共享内存则size指定为0
- flag:是构成共享区标识的参照值
- 返回值:若要建立的共享区(传入的标识符)已存在,返回共享区描述符shmid,若不存在则先建立共享区在返回描述符
共享区的操作
Unix中使用shmctl
系统调用查询共享区的状态信息,如大小、所链接的进程数、创建者标识符等。也可以修改其属性,还可以用来对共享区进行加锁或解锁。函数定义:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数说明
- shmid:是共享区的标识符
- cmd:表明在shmid指定的存储区可以执行以下命令:
IPC_STAT 对此段取shmid_ds结构存放在buf指向的结构中
IPC_SET 按buf指向的结构中的值设置此段相关的三个字段
IPC_RMID 从系统中删除该共享区
SHM_LOCK 对该共享区进行锁定,此命令只能有超级用户使用
SHM_UNLOCK 解锁该共享区,此命令只能由超级用户使用
共享区的链接
一但建立了共享区或获得了一个已有共享区的描述符后,就可以利用系统调用将该共享区链接到用户指定的某个进程的虚拟地址shmaddr上,并指定该存储区的访问属性(只读,还是可读可写)。此后进程就可以像对其他虚拟地址一样来访问该存储区。函数定义:
void *shmat(int shmid, void *addr, int flag);
共享区链接到调用进程的哪个地址上与调用函数中的addr参数和在flag中是否指定SHM_RND位有关:
- addr为0,此段链接由内核选择的第一个可用地址上
- addr非0,且未指定SHM_RND,此段链接到addr所指定的地址上
- addr非0,且指定了SHM_RND,此段链接到(addr-(addr mod SHMLBA))所表示的地址上
进程和共享区断开
当进程不需要共享内存时,可以利用系统调用shmdt()
把该区与进程断开。但是shmdt()
函数并不会删除共享区。
int shmdt(void *addr);
这里参数addr是shmat()
调用的返回值。
三,实验
实验思路就是先在主进程中创建共享区并写入数据,再利用fork()系统调用创建一个子进程,子进程链接上共享区从中读取数据。代码如下:
//3 head file about share memory
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
//head file about process : fork() wait()
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#define SHM_MODE (SHM_R | SHM_W)
#define SHM_SIZE 2048
#define MSG "Hello, son process!"
int main(){
int segment_id;
char *shared_memory;
pid_t pid;
//creat share memory
if( (segment_id=shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE))<0 ) perror("shmget error!\n");
//main process link to share memory
if( (shared_memory=shmat(segment_id, 0, 0)) == (void *)-1 ) perror("shmat error!\n");
//man process send the mesg
sprintf(shared_memory, MSG);
printf("main process send message:%s\n",&MSG);
//man process unlink to share memory
shmdt(shared_memory);
pid=fork();
if(pid<0){
perror("fork error:");
}
else if(pid==0){
printf("I am son process!\n");
if( (shared_memory=shmat(segment_id, 0, 0)) == (void *)-1 ) perror("shmat error!\n");
printf("son process get the message:%s\n",shared_memory);
shmdt(shared_memory);
}
else{
printf("I am main process!\n");
wait(NULL);
shmctl(segment_id, IPC_RMID, 0);
}
return 0;
}
输出结果:
main process send message:Hello, son process!
I am main process!
I am son process!
son process get the message:Hello, son process!