1. 共享内存特点
1)共享内存是一种最为高效的进程间通信方式,进程可以知点解读写内存,而不需要任何数据的拷贝。
2)为了在多个进程间交换信息,内核专门留出了一块内存,可以由需要访问的进程将其映射到自己的私有地址空间。
3)进程可以直接读写这一块内存而不需要进行数据的拷贝。
4)由于多个进程共享一段内存,因此需要依靠某种同步机制,如互斥锁和信号量等。
2. 共享内存实现
1)创建/打开共享内存
2)映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
3)撤销共享内存映射
4)删除内存对象
3. 共享内存实现函数
使用共享内存编程通常需要调用shmget()、shmat()、shmdt()和shmctl()几个函数。
1)创建共享内存
函数shmget()
头文件:#include<sys/ipc.h>
#include<sys/shm.h>
函数原型:int shmget(key_t key, size_t size, intshmflg)
函数参数:key 共享内存的键值,其他进程通过该值访问该共享内存,其中有个特殊值IPC_PRIVATE,表示创建当前进程的私有共享内存
size 申请的共享内存段的大小
shmflg 同open()函数的第三个参数,为共享内存设定权限,通常使用八进制表示。
函数返回值:成功:共享内存段的标识符(非负整数)
失败:-1
2)映射共享内存
函数shmat()
头文件:#include<sys/types.h>
#include<sys/shm.h>
函数原型:void *shmat(int shmid, const void*shmaddr, int shmflg)
函数参数:shmid 要映射的共享内存区标识符(即shmget()函数的返回值)
shmaddr 将共享内存映射到的指定内存地址,如果为NULL则会自动分配到一块合适的内存地址
shmflg SHM_RDONLY表示共享内存为只读,0(默认值)表示共享内存可读可写
函数返回值:成功:被映射的内存地址
失败:-1
3)撤销共享内存映射
函数shmdt()
所需头文件:#include<sys/types.h>
#include<sys/shm.h>
函数原型:int shmdt(const void *shmaddr)
函数参数:shmaddr 需要解除映射的共享内存地址
函数返回值:成功:0
失败:-1
4)删除内存对象
函数shmctl()
所需头文件:#include<sys/ipc.h>
#include<sys/shm.h>
函数原型:int shmctl(int shmid, int cmd, structshmid_ds *buf)
函数参数:shmid 共享内存区标识符(即shmget()函数的返回值)
cmd 需要对共享内存采取的操作。可取值有很多,常用的有:
IPC_STAT 将shmid_ds结构体中的数据设置为共享内存的当前关联值,即用shmid覆盖shmid_ds内的值
IPC_SET 如果进程权限允许,将共享内存的当前关联值设置为shmid_ds中给出的值
IPC_RMID 删除共享内存
buf 该参数是一个shmid_ds类型的结构体指针,使用时必须使用地址传递的方式。结构体成员很多,常用的有:
structshmid_ds
{
uid_tshm_perm.uid; /* Effective UIDof owner */
uid_tshm_perm.gid; /* Effective GIDof owner */
mode_tshm_perm.mode; /* Permissions + SHM_DESTand SHM_LOCKED flags */
……
};
函数返回值:成功:
IPC_INFO或SHM_INFO操作:内核内部记录的有关共享内存段的使用条目
SHM_STAT操作:shmid中指定的共享内存标识符
其他操作:0
失败:-1
示例代码:
文件一:
/*************************************************************************
@Author: wanghao
@Created Time : Wed 23 May 2018 04:48:19 AMPDT
@File Name: shared_memory_demo.c
@Description:
************************************************************************/
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tell.h"
int main(void)
{
intshmid;
/*CreateShared Memory with 1024 bytes size*/
if((shmid= shmget(1,1024,
IPC_CREAT|IPC_EXCL|0777))< 0){
perror("shmerror");
exit(1);
}
pid_tpid;
init();
if((pid= fork())<0){
perror("forkerror");
exit(1);
}elseif(pid >0){
/*Mapshared memory*/
int*pi = (int*)shmat(shmid,NULL,0);
if(pi== (int*) -1){
perror("shmaterror");
exit(1);
}
/*Writenumbers in shared memory*/
*pi= 111; *(pi+1) =222;
/*Relieveshared memory mapping relationships*/
shmdt(pi);
/*Noticcechild process*/
notify_pipe();
destroy_pipe();
wait(NULL);
}else{
/*Waitparent process to write*/
wait_pipe();
/*MapShared memory with shmid*/
int*pi = (int*)shmat(shmid,NULL,0);
if(pi== (int*) -1){
perror("shmaterror");
exit(1);
}
printf("start:%d,end: %d\n",*pi,*(pi+1));
/*Sameas above*/
shmdt(pi);
/*Releaseshared memory*/
shmctl(shmid,IPC_RMID,NULL);
destroy_pipe();
}
exit(0);
}
文件二:
注:该文件通过无名管道实现同步机制(管道在没写数据前进行读取发生阻塞)
#include "tell.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static int fd[2];
void init()
{
if(pipe(fd)< 0){
perror("pipeerror");
}
}
void notify_pipe()
{
charc = 'c';
if(write(fd[1],&c,1)!= 1) {
perror("notifypipe error");
}
}
void wait_pipe()
{
charc;
if(read(fd[0],&c,1)< 0) {
perror("waitpipe error");
}
}
void destroy_pipe()
{
close(fd[0]);
close(fd[1]);
}