在Linux操作系统中,共享内存是一种用于实现进程间通信(IPC)的机制,允许多个进程访问同一块内存区域。共享内存是一种高效的IPC方式,因为它允许进程直接共享数据,而无需进行数据的复制和传输。
什么是共享内存?
共享内存是操作系统中的一块内存区域,用于多个进程之间直接访问和共享数据。通过获取内存地址,进程可以实现数据的读写操作。
共享内存优点
适用范围广:可用于父子进程和非父子进程通信。
快速访问:直接访问内存,速度相对较快,无需通过文件系统。
共享内存缺点
不支持阻塞等待:无内建阻塞机制,读写端可以同时访问内存。
缺乏访问控制:无法主动停止读写,需要额外的同步机制。
共享内存允许多个进程访问同一块物理内存,这使得它成为一种快速且有效的进程间通信方式。以下是共享内存的基本原理:
内核空间分配内存: 在内核空间中,通过系统调用(如shmget)来分配一块共享内存区域。
进程连接共享内存: 进程通过系统调用(如shmat)将共享内存区域连接到它们的地址空间中。
进程访问共享内存: 连接后,进程可以直接在共享内存区域进行读写操作,就像访问自己的内存一样。
内核管理同步: 为了确保多个进程之间的同步,通常需要使用信号量等机制来管理对共享内存的访问。
#include
#include
int shmget(key_t key, size_t size, int shmflg);
key 参数:
用于标识共享内存的唯一键值,通常通过 ftok 函数生成。可以使用任意整数值,但通常会使用 ftok 函数以便唯一标识。
size 参数:
共享内存的大小,一般设置为4k的整数倍,因为操作系统在分配空间时是以4k对齐的。例如,4096表示4KB的共享内存。
shmflg 参数:
由九个权限标志构成,表示创建共享内存的方式。
IPC_CREAT:如果不存在,则创建;如果存在,则返回旧的共享内存标识符。
IPC_EXCL:与 IPC_CREAT 一同使用,表示如果存在则出错返回,即创建一个全新的共享内存。
权限位:用于设置创建的共享内存的权限,通常以八进制表示,例如,0666表示读写权限。
返回值:
成功时返回共享内存标识符(shmid),失败时返回 -1。
例如:
int shmid = shmget(key, 4096, IPC_CREAT | IPC_EXCL | 0666);
#include
#include
key_t ftok(const char *pathname, int proj_id);
pathname 参数:
文件路径名,通常使用 ftok 来生成 key。可以使用当前工作目录的路径名,如通过 getcwd 函数获取。
proj_id 参数:
项目ID,可以是任意整数值,用于进一步标识 key。
返回值:
成功时返回生成的 key,失败时返回 -1。
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid 参数:
由 shmget 返回的共享内存标识符。
shmaddr 参数:
指定连接的地址,通常为 nullptr,表示由系统自动选择一个地址。
shmflg 参数:
用于设置对共享内存的读写权限,通常为0表示读写权限。
返回值:
成功时返回连接的共享内存地址,失败时返回 (void *)-1。
#include
#include
int shmdt(const void *shmaddr);
shmaddr 参数:
由 shmat 返回的指针,代表要断开连接的共享内存。
返回值:
成功时返回 0,失败时返回 -1。
#include
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmid 参数:
由 shmget 返回的共享内存标识符。
cmd 参数:
控制命令,有三个主要取值:
IPC_STAT:获取共享内存的状态信息。
IPC_SET:设置共享内存的状态信息。
IPC_RMID:删除共享内存。
buf 参数:
指向一个保存着共享内存的模式状态和访问权限的数据结构 struct shmid_ds,用于传递和获取共享内存的信息。通常设置为 nullptr。
返回值:
成功时返回 0,失败时返回 -1。
关系:
processa.cpp 中创建并写入共享内存,然后删除共享内存。
processb.cpp 中获取共享内存,等待5秒后开始循环读取共享内存并输出。两者通过共享内存进行简单的进程间通信。
查看系统中当前存在的共享内存:
ipcs -m
这个命令会列出系统中当前存在的所有共享内存段的信息,包括内存段的ID(shmid)、大小、创建者、附加的进程数等。
删除系统中的某个共享内存:
ipcrm -m [shmid]
这个命令用于删除指定ID(shmid)的共享内存段。请确保在执行此命令之前,没有任何进程附加到该共享内存段,否则删除操作可能会失败。