您的位置:首页 > 运维架构 > Linux

Linux进程间通讯五--共享内存

2017-08-16 15:49 246 查看

一、共享内存IPC原理

  共享内存进程间通信机制主要用于实现进程间大量数据传输,共享内存是在内存(用户空间不是内核空间)中单独开辟出来的一段内存空间。下图为进程间通信示意图:

  


  两个进程在使用此共享内存空间之前,需要在进程地址空间与共享内存空间之间建立联系,即将共享内存空间挂载到进程中。

  在使用共享内存进行数据存取时,有必要使用二元信号量来同步两个进程以实现对共享内存的写操作。由于共享内存需要占用大量的内存空间,系统对共享内存做了一下限制:

#define SHMMAX 0x2000000                 /* max shared seg size (bytes) */
#define SHMMIN 1                         /* min shared seg size (bytes) */
#define SHMMNI 4096                      /* max num of segs system wide */
#define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16))
#define SHMSEG SHMMNI                    /* max shared segs per process */


二、共享内存管理

1.创建共享内存

  创建共享内存的系统调用shmget()函数声明如下:

// come from /usr/include/sys/shm.h
int shmget(key_t key, size_t size, int shmflg);


  第1个参数为key值,有ftok()函数产生,关于ftok函数在我的博客《System V IPC基础》一节有说明。;

  第2个参数size为欲创建共享内存的大小(单位为字节);

  第3个参数shmflg用来标识共享内存段的创建标识,包括:

#define IPC_CREAT       01000   /* Create key if key does not exist. */ // 如果key不存在,则创建,存在,返回ID
#define IPC_EXCL        02000   /* Fail if key exists.  */              // 如果key存在返回失败
#define IPC_NOWAIT      04000   /* Return error on wait.  */            // 如果需要等待,直接返回错误


  另外在
/usr/include/linux/shm.h
文件中还定义了另外两个选项:

/* permission flag for shmget */
#define SHM_R           0400    /* or S_IRUGO from <linux/stat.h> */    // 可读
#define SHM_W           0200    /* or S_IWUGO from <linux/stat.h> */    // 可写


  下面给出创建共享内存的代码:

#include <sys/shm.h>

key_t key = ftok("/", 3);
int shmid = shmget(key, 100, IPC_CREAT | 0666);


2.共享内存控制

  Linux系统使用shmctl()函数来实现共享内存空间的控制,包括读取状态设置状态删除操作,此函数声明如下:

// come from /usr/include/sys/shm.h
int shmctl(int shmid, int cmd, struct shmid_ds* buf);


  第1个参数shmid为要操作的共享内存标识符,由shmget()函数返回;

  第2个参数为要执行的操作,具体包括以下:

// come from /usr/include/linux/ipc.h
#define IPC_RMID 0     /* remove resource */        // 删除共享内存
#define IPC_SET  1     /* set ipc_perm options */   // 设置ipc_perm参数
#define IPC_STAT 2     /* get ipc_perm options */   // 获取ipc_perm参数
#define IPC_INFO 3     /* see ipcs */               // 获取限制信息


  如果是超级用户,还可以执行下面两个命令:

/* super user shmctl commands */
#define SHM_LOCK        11    // 锁定共享内存段
#define SHM_UNLOCK      12    // 解锁共享内存段


  第3个参数为struct shmid_ds结构的临时共享内存变量信息,此内容根据第2个参数的不同而改变。

  

  下面为删除共享内存的代码:

shmctl(shmid, IPC_RMID, NULL);


3.映射共享内存

  在进程使用一段共享内存空间之前,需要将该共享内存与当前进程建立联系,即将该共享内存映射(挂接)到当前进程。系统调用shmat()实现将一个共享内存段映射到调用进程的数据段中,并返回该内存空间首地址,其函数声明如下:

// come from /usr/include/sys/shm.h
void* shmat(int shmid, const void* shmaddr, int shmflg);


  第1个参数shmid为要操作的共享内存段首地址,该值由shmget()函数返回;

  第2个参数shmaddr指定共享内存的映射地址。如果该值为非零,则将用此值作为映射共享内存的地址,如果为0,则由系统来选择映射地址。一般都将此值设置为0

  第3个参数用来指定共享内存的访问权限映射条件

/* mode for attach */
#define SHM_RDONLY      010000  /* read-only access */
#define SHM_RND         020000  /* round attach address to SHMLBA boundary */
#define SHM_REMAP       040000  /* take-over region on attach */
#define SHM_EXEC        0100000 /* execution access */


  若设置为0,则默认有读写的权限。

  

  下面为将共享内存映射到进程空间的代码:

char* p = (char*)shmat(shmid, NULL, 0);


4.分离共享内存

  在使用完共享内存空间后,需要使用shmdt()函数将其与当前进程分离,shmdt()函数的声明如下:

// come from /usr/include/sys/shm.h
int shmdt(const void* shmaddr);


  该函数只有一个参数,即为通过映射函数shmat()返回的地址。需要注意的是在删除共享内存之前需要先分离
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: