linux ipc——shared memory
1、概念
共享内存:共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。
2、用途
. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制。共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制实现,也可以通过系统V共享内存机制实现。应用接口和原理很简单,内部机制复杂。为了实现更安全通信,往往还与信号灯等同步机制共同使用
共享内存涉及到了存储管理以及文件系统等方面的知识,深入理解其内部机制有一定的难度,关键还要紧紧抓住内核使用的重要数据结构。系统V共享内存是以文件的形式组织在特殊文件系统shm中的。通过shmget可以创建或获得共享内存的标识符。取得共享内存标识符后,要通过shmat将这个内存区映射到本进程的虚拟地址空间
3、特点
共享内存。顾名思义,这种通信方式允许多个进程共享同一块物理内存空间来实现进程之间的信息交换,其特点是没有中间环节,直接将共享的内存页面通过附接,映射到相互通信的进程各自的虚拟地址空间中,从而使多个进程可以直接访问同一个物理内存页面,如同访问自己的私有空间一样(但实质上不是私有的而是共享的)。因此这种进程间通信方式是在同一个计算机系统中的诸进程间实现通信的最快捷的方法,而它的局限性也在于此,即共享内存的诸进程必须共处同一个计算机系统,有物理内存可以共享才行。
4、用法:
发送进程:
1.使用系统调用函数shmget()创建或者获取指定key值的共享内存;
2.使用系统调用函数shmat(),将该共享内存附接到自己的虚拟地址空间;
3.将需要发送的信息写入共享内存,方法有以下几种:
①.每条信息都以追加的方式写入,可以使用C语言提供的字符串追加函数strcat(viraddr, buffer),该函数的功能是将buffer中的字符串追加到由viraddr附接的共享存储区的尾部。其中,viraddr是请求得到的共享内存的地址,buffer是用户进程中请求的用来存放信息的字符缓冲区。
②.每条信息都以覆盖的方式写入,可以使用strcpy(viraddr,buffer)函数将buffer中的字符串复制到viraddr指向的共享内存中,则该共享内存中就只有当前复制进来的信息,以前复制的信息被覆盖了。
③.共享内存定义为数值型变量,则可以将*viraddr作为数值型变量对其进行操作。例如将其赋值为0可以使用:*viradd=0。
④.共享内存定义为数值型数组,则可以将viraddr[i]作为下标变量使用。例如将其赋值为0可以使用: viradd[i]=0。
4.使用系统调用函数shmdt(),断开共享内存。
接收进程:
1. 用系统调用函数shmget();创建或者获取指定key值的共享内存;
2. 用系统调用函数shmat();将该共享内存附接到自己的程序空间;
3.将共享内存中的信息输出;或取出存放到其它数据块中;
4.使用系统调用函数shmdt();断开共享内存。
5.如果不再使用共享内存时,使用系统调用函数shmctl()将其撤消,格式为:shmctl(shmid,IPC_RMID,0);
获得一个共享存储标识符
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size,intshmflg);
功能:创建或打开一块共享内存区
参数:
key:IPC键值
size:该共享存储段的长度(字节)
shmflg:用来标识函数的行为
参数:
shmflg:用来标识函数的行为
IPC_CREAT:如果不存在就创建
IPC_EXCL:如果已经存在则返回失败
IPC_NOWAIT:调用进程会立即返回。若发生错误则返回-1。
SHM_R:可读
SHM_W:可写
返回值:
成功:返回共享内存标识符。
失败:返回-1。
共享内存映射(attach)
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr,
int shmflg);
功能:
将一个共享内存段映射到调用进程的数据段中。
参数:
shmid:共享内存标识符。
shmaddr:共享内存映射地址(若为NULL则由系 统自动指定),推荐使用NULL。
参数:
shmflg:共享内存段的访问权限和映射条件
0:共享内存具有可读可写权限。
SHM_RDONLY:只读。
SHM_RND:(shmaddr非空时才有效)
没有指定SHM_RND则此段连接到shmaddr所指定的地址上(shmaddr必需页对齐)。
指定了SHM_RND则此段连接到shmaddr- shmaddr%SHMLAB 所表示的地址上。
返回值:
成功:返回共享内存段首地址
失败:返回 -1
解除共享内存映射(detach)
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
功能:
将共享内存和当前进程分离(仅仅是断开联系并不删除共享内存)。
参数:
shmaddr:共享内存映射地址。
返回值:
成功返回 0,失败返回 -1。
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd,
struct shmid_ds *buf);
功能:共享内存空间的控制。
参数:
shmid:共享内存标识符。
cmd:函数功能的控制。
buf:shmid_ds数据类型的地址,用来存放或更改消息队列的属性。
参数:
cmd:函数功能的控制
IPC_RMID:删除。
IPC_SET:设置shmid_ds参数。
IPC_STAT:保存shmid_ds参数。
SHM_LOCK:锁定共享内存段(超级用户)。
SHM_UNLOCK:解锁共享内存段。
返回值:
成功返回 0,失败返回 -1。
5、案例
读:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define BUFSZ 2048
int main(int argc, char *argv[])
{
int shmid;
int ret;
key_t key;
char *shmadd;
key = ftok(".", 2012);
if(key==-1)
{
perror("ftok");
}
system("ipcs -m");
/*打开共享内存*/
shmid = shmget(key, BUFSZ, SHM_R|SHM_W);
if(shmid < 0)
{
perror("shmget");
exit(-1);
}
/*映射*/
shmadd = shmat(shmid, NULL, 0);
if(shmadd < 0)
{
perror("shmat");
exit(-1);
}
/*读共享内存区数据*/
printf("copy data from shared-memory\n");
printf("data = [%s]\n", shmadd);
/*分离共享内存和当前进程*/
ret = shmdt(shmadd);
if(ret < 0)
{
perror("shmdt");
exit(1);
}
else
{
printf("deleted shared-memory\n");
}
/*删除共享内存*/
shmctl(shmid, IPC_RMID, NULL);
system("ipcs -m");
return 0;
}
写:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define BUFSZ 2048
int main(int argc, char *argv[])
{
int shmid;
int ret;
key_t key;
char *shmadd;
key = ftok(".", 2012);
if(key == -1)
{
perror("ftok");
}
/*创建共享内存*/
shmid = shmget(key, BUFSZ, SHM_R|SHM_W|IPC_CREAT);
if(shmid < 0)
{
perror("shmget");
exit(-1);
}
/*映射*/
shmadd = shmat(shmid, NULL, 0);
if(shmadd < 0)
{
perror("shmat");
_exit(-1);
}
/*拷贝数据至共享内存区*/
printf("copy data to shared-memory\n");
bzero(shmadd, BUFSZ);
strcpy(shmadd, "data in shared memory\n");
return 0;
}