在操作系统中,进程间通信(IPC)是不可或缺的机制,而共享内存是其中效率最高的一种方式。它允许多个进程直接读写同一块物理内存,数据无需在内核与用户空间之间拷贝,因此速度极快。本文将详细讲解共享内存的实现原理、编程步骤,并通过完整示例带你掌握这一重要技术。
共享内存就是让多个进程可以访问同一块内存区域,是最快的IPC形式。其他IPC方式(如管道、消息队列)通常需要数据在内核空间和用户空间之间拷贝,而共享内存直接映射到进程地址空间,无需拷贝,因此性能极高。但它本身不提供同步机制,需要配合信号量等同步工具使用。
主流Unix-like系统提供两种共享内存API:System V IPC(shmget/shmat)和POSIX IPC(shm_open/mmap)。本文以System V为例讲解,并会提及mmap方式作为扩展。
使用System V共享内存通常包含以下关键步骤:
shmget(),指定键值、大小和权限标志。如果键值对应的共享内存已存在,则返回其标识符;否则创建新的。shmat(),将共享内存段附加到进程的虚拟地址空间,返回指向该内存的指针。shmdt()将共享内存从当前进程分离。shmctl()进行控制操作,如删除共享内存段。下面通过一个简单的生产者-消费者程序演示共享内存的使用。生产者向共享内存写入数据,消费者从共享内存读取数据。为了同步,我们使用System V信号量(semget/semop)来保证互斥访问。
// producer.c - 生产者#include #include #include #include #include #include #include #define SHM_KEY 1234#define SEM_KEY 5678#define SHM_SIZE 1024union semun {int val;struct semid_ds *buf;unsigned short *array;};int main() {int shmid, semid;char *data;struct sembuf sb = {0, -1, 0}; // 用于P操作// 创建共享内存shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);if (shmid < 0) { perror("shmget"); exit(1); }// 映射共享内存data = shmat(shmid, NULL, 0);if (data == (char *)-1) { perror("shmat"); exit(1); }// 创建信号量集(含1个信号量)semid = semget(SEM_KEY, 1, IPC_CREAT | 0666);if (semid < 0) { perror("semget"); exit(1); }// 初始化信号量为1(二进制信号量)union semun arg;arg.val = 1;if (semctl(semid, 0, SETVAL, arg) < 0) { perror("semctl"); exit(1); }// 生产者写入数据const char *message = "Hello from producer!";sb.sem_op = -1; // P操作,获取锁if (semop(semid, &sb, 1) < 0) { perror("semop lock"); exit(1); }strcpy(data, message);printf("生产者写入: %s", message);sb.sem_op = 1; // V操作,释放锁if (semop(semid, &sb, 1) < 0) { perror("semop unlock"); exit(1); }// 分离共享内存shmdt(data);return 0;} // consumer.c - 消费者#include #include #include #include #include #include #define SHM_KEY 1234#define SEM_KEY 5678int main() {int shmid, semid;char *data;struct sembuf sb = {0, -1, 0};// 获取共享内存shmid = shmget(SHM_KEY, 0, 0666);if (shmid < 0) { perror("shmget"); exit(1); }// 映射共享内存data = shmat(shmid, NULL, 0);if (data == (char *)-1) { perror("shmat"); exit(1); }// 获取信号量semid = semget(SEM_KEY, 0, 0666);if (semid < 0) { perror("semget"); exit(1); }// 消费者读取数据sb.sem_op = -1; // P操作if (semop(semid, &sb, 1) < 0) { perror("semop lock"); exit(1); }printf("消费者读取: %s", data);sb.sem_op = 1; // V操作if (semop(semid, &sb, 1) < 0) { perror("semop unlock"); exit(1); }// 分离共享内存shmdt(data);// 删除共享内存和信号量(实际生产环境由专门的清理进程处理)// shmctl(shmid, IPC_RMID, NULL);// semctl(semid, 0, IPC_RMID);return 0;} 编译运行:先运行producer,再运行consumer。可以看到消费者正确读取到生产者写入的消息。
除了System V方式,mmap系统调用也可以创建共享内存映射。它可以将一个文件或匿名内存映射到多个进程的地址空间,从而实现共享。通过mmap配合MAP_SHARED标志,可以实现父子进程或无亲缘关系进程之间的共享内存。这种方式更现代,也更灵活,常与POSIX信号量结合使用。
shmctl IPC_RMID),否则会残留在系统中(可用ipcs查看,ipcrm删除)。/proc/sys/kernel/shmmax等参数。共享内存是进程间通信的利器,尤其适合大数据量传输的场景。本文从原理到代码,详细介绍了System V共享内存的使用,并扩展了mmap方式。掌握共享内存和IPC相关知识,对于理解操作系统底层、编写高性能程序至关重要。希望本文能帮助你彻底搞懂共享内存!
本文由主机测评网于2026-03-16发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://vpshk.cn/20260331585.html