共享内存(ShareMemory)
共享内存允许两个或多个进程共享一个给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,因此,这是最快的一种IPC方式。
使用共享内存的关键点在于:多个进程同步访问一个给定的存储区,若服务器进程正在把数据放入共享内存区,则它在做完这一操作之间,客户进程不能取这些数据。可以使用信号量、记录锁或者互斥量来完成同步过程。
数据结构
#include <shm.h>
struct ipc_perm
{
__kernel_key_t key;
__kernel_uid_t uid;
__kernel_gid_t gid;
__kernel_uid_t cuid;
__kernel_gid_t cgid;
__kernel_mode_t mode;
unsigned short seq;
};
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
1.创建或者引用共享内存
#include <sys/shm.h>
int shmget(key_t key, size_t size, int flag);
2.控制共享内存
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
cmd参数
IPC_STAT
IPC_SET
IPC_RMID
3.一旦创建了一个共享存储段,进程就可以调用shmat将其连接到它的地址空间中。
#include <sys/shm.h>
void *shmat(int shmid, const void *addr, int flag);
注意:
如果addr为0,则此段连接到由内核选择的第一个可用地址上,这也是推荐的方式
如果addr非0,且没有设置SHM_RND,将此段连接到addr所指定的地址上
如果addr非0,且设置了SHM_RND,则此段连接到(addr-(addr mod SHMLBA))所表示的地址上。
SHM_RND表示“取整”,SHMLBA表示“低边界地址倍数”,它总是2的平方。
该算式是将地址向下取最近1个SHMLBA的倍数。
#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
/* 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 */
/* super user shmctl commands */
#define SHM_LOCK 11
#define SHM_UNLOCK 12
除非只计划在一种硬件上运行应用程序,否则不应设置共享内存所要连接的地址!
而是应当设置addr为0,由系统自动选择地址。
4.分离共享内存段
#include <sys/shm.h>
int shmdt(const void *addr);
分离共享内存,并不是删除共享内存,该标识符仍然存在,只是将shmid_ds结构中的shm_nattch计数器减1,直到某个进程调用shmctl,设置cmd为IPC_RMID时才会删除。
参考书目:《APUE》