顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中,所有的进程都可以访问共享内存中的地址。
共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区。在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni等,可以手工对其调整,但不推荐这样做。
共享内存有两种方式,即 shm 和 mmap 方式。前者直接共享物理内存,后者通过一个中间文件间接共享内存
#include
#include
int shmget(key_t key, size_t size, int shmflg)
key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。
在IPC的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key)。通过“键”,进程能够识别所用的对象。“键”与IPC对象的关系就如同文件名称之于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够共用一个文件。而在IPC的通讯模式下,通过“键”的使用也使得一个IPC对象能为多个进程所共用。
size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。所以如果一段进程只申请一块只有一个字节的内存,内存也会分配整整一页(在i386机器中一页的缺省大小PACE_SIZE=4096字节)这样,新创建的共享内存的大小实际上是从size这个参数调整而来的页面大小。即如果size为1至4096,则实际申请到的共享内存大小为4K(一页);4097到8192,则实际申请到的共享内存大小为8K(两页),依此类推。
shmflg主要和一些标志有关。其中有效的包括IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。
- IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则打开操作。
- IPC_EXCL 只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。
成功: 共享内存的标识符;
失败: -1,errno储存错误原因。
EINVAL 参数size小于SHMMIN或大于SHMMAX。
EEXIST 预建立key所致的共享内存,但已经存在。
EIDRM 参数key所致的共享内存已经删除。
ENOSPC 超过了系统允许建立的共享内存的最大值(SHMALL )。
ENOENT 参数key所指的共享内存不存在,参数shmflg也未设IPC_CREAT位。
EACCES 没有权限。
ENOMEM 核心内存不足。
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
成功: 一个指向共享内存第一个字节的指针
失败: -1,errno储存错误原因。
EACCES : 没有权限
EIDRM : 共享内存已经被删除
EINVAL : invalid shmid value, or invalid shmaddr value, or can’t attach segment at shmaddr, or SHM_REMAP was specified and shmaddr was NULL.
ENOMEM : Could not allocate memory for the descriptor or for the page table
#include
#include
int shmdt(const void *shmaddr);
成功: 0
失败: -1,errno储存错误原因。
EINVAL:There is no shared memory segment attached at shmaddr; or
shmaddr is not aligned on a page boundary
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
command | 说明 |
---|---|
IPC_STAT | 设定 共享内存的属性 |
IPC_SET | 读取共享内存的属性 |
IPC_RMID | 删除共享内存,buf设置为NULL |
SHM_LOCK | 锁定共享内存段( 超级用户 )。 用于锁定内存,禁止内存交换。并不代表共享内存被锁定后禁止其它进程访问。 其真正的意义是:被锁定的内存不允许被交换到虚拟内存中。这样做的优势在于让共享内存一直处于内存中,从而提高程序性能。 |
SHM_UNLOCK | 解锁共享内存段。 |
注意:若选择删除共享内存,第三个参数传NULL
shmid_ds 构造体
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
struct ipc_perm {
key_t __key; /* Key supplied to shmget(2) */
uid_t uid; /* Effective UID of owner */
gid_t gid; /* Effective GID of owner */
uid_t cuid; /* Effective UID of creator */
gid_t cgid; /* Effective GID of creator */
unsigned short mode; /* Permissions + SHM_DEST and
SHM_LOCKED flags */
unsigned short __seq; /* Sequence number */
};
成功: 0
失败: -1,errno储存错误原因。
EACCESS:参数cmd为IPC_STAT,确无权限读取该共享内存
EFAULT:参数buf指向无效的内存地址
EIDRM:标识符为msqid的共享内存已被删除
EINVAL:无效的参数cmd或shmid
EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行