共享存储
共享存储允许两个或更多进程共享一给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,所以这是最快的一种IPC。
一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传递就不再涉及内核。但往该共享内存区存放信息或从中取走信息的进程间需要某种形式的同步。(通常,信号量、记录锁被用来实现对共享存储访问的同步)
shmget函数
shmget函数创建一个新的共享内存区,或者访问一个已存在的共享内存区。
#include <sys/shm.h>
int shmget (key_t key, size_t size, int oflag) ;
返回值是一个称为共享内存区标识符的整数,其他三个shmXXX函数就用它来指代这个内存区。
参数key既可以是ftok的返回值,也可以是IPC_PRIVATE
参数size是指定内存区的大小。(若访问已存在的内存区,则size应为0)
参数oflag是读写权限值的组合。
当实际操作为创建一个新的共享内存区时,该内存区被初始化为size字节的0。
shmat函数
由shmget函数创建或打开一个共享内存区后,通过调用shmat把它附接到调用进程的地址空间。
#include <sys/shm.h>
void* shmat (int shmid, const void* shmaddr, int flag) ;
参数shmid是由shmget返回的标识符。
shmat的返回值是所指定的共享内存区在调用进程内的起始地址。(一般把参数shmaddr置为NULL,让系统替调用者选择地址)
参数flag可以指定SHM_RDONLY值,它限定只读访问。(默认可同时读写)
shmdt函数
当一个进程完成某个共享内存区的使用时,它可以调用shmdt断接这个内存区。
#include <sys/shm.h>
int shmdt (const void* shmaddr) ;
当一个进程终止时,它当前附接着的所有共享内存区都自动断接掉。
注意,本函数只是断开关联,并不删除所指定的共享内存区。删除工作通过以IPC_RMID命令调用shmctl完成。(XSI IPC都是随内核持续的)
shmctl函数
shmctl提供了对一个共享内存区的多种操作。
#include <sys/shm.h>
int shmctl (int shmid, int cmd, struct shmid_ds* buff) ;
参数cmd:
IPC_RMID 从系统中删除该共享存储段。因为每个共享存储段有一个连接计数器,所以除非使用该段的最后一个进程终止或与该段脱接,否则不会实际上删除该存储段。但不管此段是否仍在使用,该段标识符立即被删除,所以不能再用shmat与该段连接。
【示例】
//共享内存IPC简单示例
//
//使用方法:程序名 路径名 消息内容
//
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
int
main(int argc, char** argv)
{
int shmid ; //共享内存区的标识符
size_t shmSize = 512 ; //共享内存的大小
char* shmaddr ; //共享内存的指针
int i = 0 ;
if (argc != 3)
{
perror("parameter error!\n") ;
exit(0) ;
}
//创建共享内存
shmid = shmget(ftok(argv[1], 0), shmSize, IPC_CREAT) ;
//获取共享内存的指针(把共享内存映射到本进程地址空间)
shmaddr = shmat(shmid, NULL, 0) ;
//向共享内存中写入数据
strcpy(shmaddr, argv[2]) ;
//断开与共享内存的连接
shmdt(shmaddr) ;
exit(0) ;
}
//共享内存IPC简单示例
//访问共享内存
//
//使用方法:程序名 同一路径名 消息内容
//
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
int
main(int argc, char** argv)
{
int shmid ; //共享内存区的标识符
key_t shmkey ; //共享内存区的key
char msgbuf[512] ; //存储从共享存储区提取的消息
char* shmaddr ; //共享内存的指针
if (argc != 2)
{
perror("parameter error!\n") ;
exit(0) ;
}
//打开共享内存
shmid = shmget(ftok(argv[1], 0), 0, 0) ;
//把共享内存映射到本进程地址空间
shmaddr = shmat(shmid, NULL, 0) ;
//读取共享内存中的消息
printf("The message in the share memory : %s\n", shmaddr) ;
//断开与共享内存的连接
shmdt(shmaddr) ;
//删除共享内存
shmctl(shmid, IPC_RMID, NULL) ;
exit(0) ;
}