Linux学习笔记(十五)--共享内存

张开发
2026/4/10 12:16:08 15 分钟阅读

分享文章

Linux学习笔记(十五)--共享内存
system V 共享内存核心概念System V共享内存允许多个不相关的进程访问同一块物理内存区域从而实现高效的数据共享。它是最快的进程间通信IPC方式之一因为数据不需要在进程间复制。关键函数shmget作用创建/获取共享内存段#include sys/ipc.h #include sys/shm.h int shmget(key_t key, size_t size, int shmflg);key: 标识符可以用ftok()生成或使用IPC_PRIVATEsize: 共享内存大小字节shmflg: 权限标志如IPC_CREAT | 0666标志位IPC_CREAT(单独使用)如果申请共享内存不存在就创建存在就获取并返回IPC_CREAT|IPC_EXCL如果申请共享内存不存在就创建如果存在就出错返回。确保如果我们申请成功了一个共享内存那么这个共享内存一定是新的。IPC_EXCL不单独使用key具有唯一性能够让不同进程进行唯一性标识。第一个进程可以通过key创建共享内存第二个之后的key只要拿着同一个key就可以和第一个进程看到同一个共享内存。对于一个已经创建好的共享内存key在共享内存的描述对象中。#include sys/types.h #include sys/ipc.h key_t ftok(const char *pathname, int proj_id);pathname​存在的文件路径名proj_id​项目标识符1-255之间的整数shmid共享内存标识符shmid是 Linux System V 共享内存机制中的一个整型句柄由操作系统内核在创建或获取共享内存段时返回用于在单个进程内部唯一标识和管理该共享内存资源。获取方式#include sys/ipc.h #include sys/shm.h // 通过 shmget() 系统调用获得 int shmid shmget(key, size, flags); // 成功时返回一个非负整数就是 shmid // 失败时返回 -1shmid与key的区别key是操作系统内标定的唯一性而shmid是只在你的进程内用来表示资源的唯一性。key是全局的、命名的。它是为了让多个独立的进程能够找到彼此。如果两个进程使用相同的 key调用 shmget它们会得到同一个共享内存段的 shmid。shmid是本地的、句柄化的。它是进程在获取到共享内存后在自己进程空间内用来引用和操作这个资源的一个临时标识。同一个共享内存段在不同的进程中可能有不同的 shmid值虽然通常相同但不能依赖于此。关键是它们都指向内核中的同一个对象。特性keyshmid数据类型key_t(通常是一个整数)int生成方式1. 通过ftok函数生成。2. 使用固定常量IPC_PRIVATE。3. 直接指定一个已知整数。由shmget系统调用成功返回。目的与作用外部标识。用于在系统范围内唯一命名一个共享内存资源。不同进程通过约定使用同一个key来访问同一块共享内存。内部句柄。用于在单个进程内部标识一个已连接的共享内存对象。它是进程对该资源进行操作的控制令牌。生命周期是静态的、预定义的标识符。只要约定好就保持不变。是动态的、每次创建或获取时由内核返回的。在进程生命周期内有效进程结束后就失去意义(但共享内存段本身可能还存在)。类比类似于文件路径(如/home/shared/data)。任何知道这个路径的程序都能找到这个文件。类似于文件描述符(如fdopen(...)返回的整数)。程序用这个描述符来读写、关闭文件。在API中的使用主要用于shmget的第一个参数用于“寻找”或“创建”共享内存段。1. 用于shmat(附加内存到进程空间)2. 用于shmdt(从进程空间分离)3. 用于shmctl(控制操作如获取状态、删除等)shmat作用附加到进程地址空间void *shmat(int shmid, const void *shmaddr, int shmflg);返回共享内存在进程中的起始地址shmaddr通常设为NULL由系统选择地址shmdt作用分离共享内存int shmdt(const void *shmaddr);shmctl作用控制操作int shmctl(int shmid, int cmd, struct shmid_ds *buf);cmd:IPC_STAT: 获取状态信息IPC_SET: 设置参数IPC_RMID: 删除共享内存段基本使用示例写入进程#include stdio.h #include sys/ipc.h #include sys/shm.h #include string.h int main() { // 1. 创建共享内存 key_t key ftok(shmfile, 65); int shmid shmget(key, 1024, 0666 | IPC_CREAT); // 2. 附加到进程 char *str (char*)shmat(shmid, NULL, 0); // 3. 写入数据 strcpy(str, Hello from writer!); printf(Data written: %s\n, str); // 4. 分离 shmdt(str); return 0; }读取进程#include stdio.h #include sys/ipc.h #include sys/shm.h int main() { // 1. 获取共享内存 key_t key ftok(shmfile, 65); int shmid shmget(key, 1024, 0666); // 2. 附加到进程 char *str (char*)shmat(shmid, NULL, 0); // 3. 读取数据 printf(Data read: %s\n, str); // 4. 分离 shmdt(str); // 5. 删除共享内存 shmctl(shmid, IPC_RMID, NULL); return 0; }查看System V共享内存段状态ipcs -mkey shmid owner perms bytes nattch status 0x00000000 32768 alice 600 524288 2 destkey​共享内存的键值shmid​共享内存标识符owner​所有者用户名perms​权限位八进制bytes​共享内存大小字节nattch​附加进程数status​状态标志共享内存的生命周期是随内核的用户不主动关闭共享内存就会一直存在除非内核重启。删除共享内存ipcrm -m shmid通信方式通信方式两个进程通过映射同一块物理内存区域共享内存来直接交换数据。特点核心优势零拷贝、高性能。数据写入共享内存后对方进程能直接看到无需经过内核态的系统调用就像访问自己的内存一样快。技术本质它绕过了操作系统内核的干预实现了进程间的“内存共享”是最高效的IPC方式之一。共享内存没有进行同步与互斥。system V消息队列核心概念System V消息队列是一个内核维护的链表结构允许进程以消息的形式交换数据。每个消息都有类型和优先级接收进程可以按类型选择性接收。关键函数msgget作用创建/获取消息队列#include sys/types.h #include sys/ipc.h #include sys/msg.h int msgget(key_t key, int msgflg);返回值: 消息队列标识符正整数msgflg:IPC_CREAT: 不存在则创建IPC_EXCL: 与IPC_CREAT一起使用存在则失败权限位: 如0666msgsnd作用发送消息int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);msgp: 指向消息结构的指针msgsz: 消息数据部分的长度不包括mtypemsgflg:0: 阻塞模式IPC_NOWAIT: 非阻塞模式msgrcv作用接收消息ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);msgtyp:1 0: 接收队列中第一条消息2 0: 接收类型为msgtyp的第一条消息3 0: 接收类型≤|msgtyp|的最小类型的消息msgflg:1IPC_NOWAIT: 非阻塞2MSG_NOERROR: 消息过长时截断而不报错3MSG_EXCEPT: 接收类型≠msgtyp的消息msgctl作用 控制操作int msgctl(int msqid, int cmd, struct msqid_ds *buf);cmd:1IPC_STAT: 获取状态2IPC_SET: 设置参数3IPC_RMID: 立即删除消息队列struct msqid_ds这个结构体包含了消息队列的完整状态信息。#include sys/msg.h struct msqid_ds { struct ipc_perm msg_perm; // 权限结构 time_t msg_stime; // 最后发送时间 time_t msg_rtime; // 最后接收时间 time_t msg_ctime; // 最后修改时间 unsigned long __msg_cbytes; // 当前队列字节数 msgqnum_t msg_qnum; // 当前队列消息数 msglen_t msg_qbytes; // 队列最大字节数 pid_t msg_lspid; // 最后发送进程PID pid_t msg_lrpid; // 最后接收进程PID };struct ipc_perm这个是所有System V IPC结构共用的权限控制结构。#include sys/ipc.h struct ipc_perm { key_t __key; // 队列的key uid_t uid; // 所有者用户ID gid_t gid; // 所有者组ID uid_t cuid; // 创建者用户ID gid_t cgid; // 创建者组ID unsigned short mode; // 权限模式 unsigned short __seq; // 序列号 };上述两个结构体System V IPC管理和监控的基础。

更多文章