进程间通信——IPC之共享内存

相关函数
1.创建共享内存shmget
原型:int shmget(key_t key, size_t size, int shmflg) 返回值: 创建成功,则返回一个非负整数,即共享内存标识; 如果失败,则返回-1.
参数:
key: //程序需要提供一个参数key,它为共享内存段提供一个外部名。(每个IPC对象都与一个键 即key相关联,然后此键再由内核变换为标识符)。还有一个特殊的键值IPC_PRIVATE, 它用于创建一个只属于该创建进程的新共享内存,通常不会用到;
该函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg) 返回值:调用成功返回挂载的虚拟地址空间起始地址,失败返回NULL
参数:
int shmid //是由shmget函数返回的共享内存标识。
const void *shmaddr //指定共享内存连接到当前进程中的地址位置,通常为0,表示让系统来选择 共享内存的地址。
int shmflg //是一组标志位,通常为0。它还可取:SHM_RND,用以决定是否将当前共享内存段连接到指定的shmaddr上。该参数和shm_addr联合使用,用来控制共享内存连接的地址,除非只计划在一种硬件上运行应用程序,否则不要这样指定。填0让操作系统自己选择是更好的方式。
SHM_RDONLY单独使用则是指让它使连接的内存段只读,否则以读写方式连接此内存段
3. 与共享内存段分离 shmdt
原型:int shmdt(const void *shmaddr)
参数:
只是使得该共享内存对当前进程不再可用。
4. shmctl 共享内存控制函数
#include <sys/ipc.h> #include <sys/shm.h> 原型: int shmctl(int shmid, int cmd, struct shmid_ds *buf)
参数:
struct shmid_ds { uid_t shm_perm.uid; uid_t shm_perm.gid; mode_t shm_perm.mode; }
简单使用
简单用共享内存来再两进程间交换数据,比如交换一个结构体
代码如下:

#include <sys/ipc.h> #include <sys/shm.h> typedef struct Stu { int age; char name[10]; }student; int main( void) { student s; strcpy(s.name, "jack"); //创建共享内存段 int shmid = shmget(1234, 8, IPC_CREAT|0644); if( shmid == -1){ return 0; } //挂载到进程的地址空间 student* p = (student*)shmat( shmid, NULL, 0); int i =0; while( i<20 ) { s.age = i++; memcpy(p, &s, sizeof(student)); //写到共享段中 sleep(1); } //从系统中删除该共享内存,如果不删除,此进程结束后共享内存表示还存在 if( shmctl( shmid, IPC_RMID, 0) < 0 ){ printf("shmctl error"); } return 0; }

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ipc.h> #include <sys/shm.h> typedef struct Stu { int age; char name[10]; }student; int main( void) { int shmid = shmget(1234, 8, 0); if( shmid == -1){ return 0;} student *p = (student *)shmat( shmid, 0, 0); int i=1; while(i++) { if(i==5){ //对共享内存操作结束时,调用shmdt与该内存段分离,只是分离不会删除 if( shmdt(p) == -1 ){ printf("shmdt error");} break;//分离后,下面不能有对该内存的操作 } printf(" age= %d, name= %s\n", p->age, p->name); sleep(1); } return 0; }
执行结果如下:
小结
优点:我们可以看到使用共享内存进行进程间的通信真的是方便而高效,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。
上面只是共享内存的一些简单的应用,当多个进程对共享内存进行访问时,并没有保证同步,所以我们还需要用其它的机制来实现它的同步机制,要解决此,通常会用到信号量(PV操作)来实现。但要基于此的实现,前提还需要熟悉信号量的操作以及这里的共享内存使用。要用共享内存模拟做出一个带同步机制"先进先出"的消息通道,对我等萌新并不太容易,所以还得放到以后再实现了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2019-01-16 Java获取Date类型-针对SQL语句