现在的位置: 首页 > 综合 > 正文

linux进程间通信6——共享内存

2013年11月16日 ⁄ 综合 ⁄ 共 3182字 ⁄ 字号 评论关闭

一、共享内存概述

    共享内存区是最快的可用IPC形式。它允许多个不相关的进程去访问同一部分逻辑内存。如果需要在两个运行中的进程之间传输数据,共享内存将是一种效率极高的解决方案。一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传输就不再涉及内核。这样就可以减少系统调用时间,提高程序效率。

    共享内存是由IPC为一个进程创建的一个特殊的地址范围,它将出现在进程的地址空间中。其他进程可以把同一段共享内存段连接到它们自己的地址空间里去。所有进程都可以访问共享内存中的地址。如果一个进程向这段共享内存写了数据,所做的改动会立刻被有访问同一段共享内存的其他进程看到。

要注意的是共享内存本身没有提供任何同步功能。也就是说,在第一个进程结束对共享内存的写操作之前,并没有什么自动功能能够预防第二个进程开始对它进行读操作。共享内存的访问同步问题必须由程序员负责。可选的同步方式有互斥锁、条件变量、读写锁、纪录锁、信号

      共享内存区分为System V共享内存区和Posix共享内存区。本节介绍System V共享内存区。

 

二、共享内存区结构

      和其他XSI IPC一样,内核为每个共享存储段设置一个shmid_ds结构。

struct shmid_ds

{

     struct ipc_perm   shm_perm;    /*operation perms操作权限*/

     int               shm_segez;    /*size of segment段长度大小*/

     time_t           shm_atime;    /*last attach time最近attach时间*/

     time_t           shm_dtime;    /*last detach time最近detach时间*/

     time_t           shm_ctime;    /*last change time最近change时间*/

     unsigned short   shm_lpid;      /*pid of creator*/

     unsigned short   shm_cpid;     /*pid of last operator*/

     short              shm_nattch;   /*no.of current attaches*/

…….

 };

其中ipc_perm是我们在XSI IPC里介绍的权限结构。

struct ipc_perm

{

      key_t     key; 

      ushort    uid; /*owner euid and egid*/

      ushort    gid;

      ushort    cuid; /*creator euid and egid*/

      ushort    cgid;

      ushort    mode; /*lower 9 bits of shmflg*/

      ushort    seq; /*sequence number*/

};

 

三、共享内存区函数

   shmget函数创建一个尚未存在的共享内存区,或者访问一个已存在的共享内存区。

1

名称:

shmget

功能:

获得一个共享存储标识符

头文件:

#inlcude <sys/shm.h>

#include <sys/ipc.h>

函数原形:

int shmget(key_t key,int size,int shmflg);

参数:

ket

size内存区大小

shmflg权限值

返回值:

若成功则返回共享内存id,若出错则为-1

      

key为共享存储的外部键,通过ftok获得。

size是该共享存储段的长度。如果正在创建一个新段,则必须指定其size。如果正在引用一个现存的段,则将size指定为0。当创建一新段时,段内的内容初始化为0

shmflg由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的。当需要创建新的共享内存段时需要与IPC_CREAT标志按位或。设置IPC_CREAT标志并传递已存在的共享内存段不会产生错误。如果想创建一个读一无二的共享内存区可以与IPC_CREAT|IPC_EXCL按位或,这样如果系统以存在这个共享内存区,shmget函数就会报错。

还有两个选项:

SHM_R:可读

SHM_W:可写

System V共享内存区至少具有随内核持续性,因此程序结束该共享内存区还存在。

 

在共享内存段刚被创建的时候,任何进程还都不能访问它。为了建立这个共享内存段的访问渠道,必须由我们来把它连接到某个进程的地址空间。这项工作是由shmat函数完成的。

2

名称:

shmat

功能:

将共享内存段连接到他的地址空间

头文件:

#include <sys/ipc.h>

#inlcude <sys/shm.h>

函数原形:

void *shmat(int shm_id,void *shm_addr,int shmflg);

参数:

shm_id标识码

shm_addr连接到的地址

shmflg 标志位

返回值:

若成功则为指向共享存储的指针,若出错则为-1

      

shm_idshmget返回的共享内存标识码。

shm_addr是把共享内存连接到当前进程去的时候准备放置它的那个地址。这通常是一个空指针,表示把选择共享内存出现处的地址这项工作交给系统去完成。

shmflg是一组按位或的标志。它的两个可能值是SHM_RND(这个标志与shm_addr一起控制着共享连接的地址)SHM_RDONLY(它使连接的共享内存成为一个只读区间)。很少有需要控制共享内存连接的地址的情况,一般都是由系统替你挑选一个地址,否则就会使你的软件对硬件的依赖性过高。

      shmat的返回值是该段所连接的实际地址,如果出错则返回-1。如果shmat成功执行,那么内核将该共享存储段shmid_ds结构的shm_nattch计算器加1

      缺省情况下,只要调用进程具有某个共享内存区的读写权限,它附接该内存区后就能够同时读写该内存区。只有flag参数指定SHM_RDONLY值时,它以只读方式访问。

 

当一个进程完成某个共享内存区的使用时,它可调用shmdt函数脱离与这个共享内存区的联系。

3

名称:

shmdt

功能:

脱接共享存储段

头文件:

#include <sys/ipc.h>

#inlcude <sys/shm.h>

函数原形:

int shmdt(void *shmaddr);

参数:

shmaddr

返回值:

若成功则为0,若出错则为-1

      

当一个进程终止时,它的所有当前附接着的共享内存区都自动断接掉。注意本函数调用并不是从系统中删除其标识符以及其数据结构。该标识符仍然存在,直至某个进程调用shmctl特地删除它。

     addr参数是以前调用shmat时的返回值。如果成功,shmdt将使相关shmid_ds结构中的shm_nattch计数其减1

在创建子进程的时候注意以下几点:

(1)、子进程继承父进程挂载的共享内存

(2)、如果调用exec执行一个新的程序,则所有挂载的共享内存将被卸载

(3)、如果在某个进程中调用了exit()函数,所有挂载的共享内存将与当前进程脱离关系

4

名称:

shmctl

功能:

对共享存储段执行多种操作

头文件:

#include <sys/ipc.h>

#inlcude <sys/shm.h>

函数原形:

int shmctl(int shm_id,int command,struct shmid_ds *buf);

参数:

shm_id共享内存标

抱歉!评论已关闭.