Linux基础入门--进程间通信--共享内存
1.共享内存IPC原理
共享内存进程间通信机制主要用于实现进程间大量的数据传输,共享内存是在内存单独开辟的一段内存空间,这段内存空间有自己特有的数据结构,包括访问权限,大小和最近访问的时间等。该数据结构定义如下:
//include /usr/include/bit/shm.h
struct shmid_ds {
struct ipc_perm shm_perm; //操作权限
int shm_segsz; //段长度大小
_kernel_time_t shm_atime; //最近attach时间
_kernel_time_t shm_dtime; //最近detach时间
_kernel_time_t shm_ctime; //最近change时间
_kernel_ipc_pid_t shm_cpid; //创建者pid
_kernel_ipc_pid_t shm_lpid; //最近操作pid
unsigned short shm_nattch;
unsigned short shm_unused;
void *shm_unused2;
void *shm_unused3;
}
两个进程在使用此共享内存空间之前,需要在进程地址空间与共享内存空间之间建立联系,即将共享内存空间挂载到进程中。
在使用共享内存进行数据存取时,有必要使用二元信号量来同步两个进程以实现对共享内存的写操作。由于共享内存需要占用大量的内存空间,系统对共享内存做了以下限制:
// include /usr/include/linux/shm.h
#define SHMMAX 0x20000000 //最大共享段大小
#define SHMMIN 1 //最小共享段大小
#define SHMMNI 4096
共享内存与管道对比,使用管道从一个文件传输信息到另一个文件需要复制4次(分别是服务器端将信息从相应文件复制到server临时缓冲区,从临时缓冲区到PIPE或FIFO,客户端将信息从PIPE或FIFO复制到client的临时缓冲区,再从临时缓冲区将信息写到输出文件),而使用共享内存则只需要两次复制,且不涉及内核态与用户态的切换,在很大程度上提高了数据存取的效率。
2.共享内存管理
2.1 创建共享内存
创建共享内存的系统调用shmget函数声明如下:
extern int shmget(key_t _key, size_t _size, int _shmflg);
第1个参数为key_t类型的key值,一般由ftok函数产生,第2个参数size为欲创建的共享内存段大小(单位为字节),第3个参数shmflg用来标识共享内存段的创建标识,包括以下:
//include /usr/include/linux/ipc.h
#define IPC_CREAT 01000 //如果不存在就创建
#define IPC_EXCL 02000 //如果存在则返回失败
#define IPC_NOWAIT 04000 //不等待直接返回
#define SHM_R 0400 //可读
#define SHM_W 0200 //可写
2.2 共享内存控制
使用shmctl函数来实现共享内存空间的控制,包括读取状态,设置状态和删除操作:
extern int shmctl(int _shmid, int _cmd, struct shmid_ds *buf);
第1个参数为要操作的共享内存标识符,该值一般由shmget函数返回
第2个参数为要执行的操作,包括以下:
#define IPC_RMID 0 //删除
#define IPC_SET 1 //设置
#define IPC_STAT 2 //获取
#define IPC_INFO 3 //查看
#define SHM_LOCK 11 //锁定共享内存
#define SHM_UNLOCK 12 //解锁共享内存
第3个参数为struct shmid_ds结构的临时共享内存变量信息
2.3 映射共享内存对象
在进程使用一段共享内存空间钱,需要将该共享内存与当前进程建立联系,即将该共享内存映射到当前进程。系统调用shma()实现将一个共享内存段映射到调用进程的数据段中,并返回该内存空间首地址。
extern voud *shmat(int _shmid, const void *_shmaddr, int _shmflg);
如果执行成功,将返回共享内存段首地址。
第1个参数_shmid为要操作的共享内存标识符,该值一般由shmget函数返回。
第2个参数shmaddr指定共享内存的映射地址。如果该值为非零,则将用此值作为映射共享内存的地址,如果此值为0,则由系统来选择映射的地址。一般都将此值设置为0.
第3个参数用来指定共享内存段的访问权限和映射条件:
//include /usr/include/linux/shm.h
#define SHM_RDONLY 010000 //read-only access
#define SHM_RND 020000
#define SHM_REMAP 040000
#define SHM_EXEC 0100000
2.4 分离共享内存对象
在使用完毕共享内存空间后,需要使用shmdt函数调用将其与当前进程分离。shmdt函数声明如下:
extern int shmdt (_const void *_shmaddr);
此函数只有一个参数,即与当前进程分离的共享内存标识ID
共享内存在父子进程间遵循以下约定。
使用fork()函数创建一个子进程后,该进程继承父亲进程挂载的共享内存。
如果调用exec执行一个新的程序,则所有挂载的共享内存将被自动卸载
如果在某个进程中调用了exit()函数,所有挂载的共享内存将与当前进程脱离关系
温馨提示:
以上文章描述如有不清晰之处,欢迎在评论区评论,如有时间,会第一时间回复,谢谢!
来源:CSDN
作者:香蕉一号
链接:https://blog.csdn.net/qq_20677327/article/details/103882245