版权声明:guojawee https://blog.csdn.net/weixin_36750623/article/details/83384612
1.最快的IPC通信方式
- 共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。
图1:用管道或者消息队列传递数据
图2:用共享内存传递数据
2.相关API
[1]shmget
int shmget(key_t key, size_t size, int shmflg); //创建或打开
[2]shmat:将共享内存段连接到进程地址空间
- [说明1]shmget创建/打开共享内存后,必须使用shmat将该共享内存连接到进程的地址空间,以便进程使用。不适用shmat,进程无法使用该共享内存。
- [说明2]每个进程shmat同一个内存段后得到的地址不一样–它们都属于自己的共享内存地址)
- 函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg); - 返回值
失败:返回-1;
成功:返回一个指针p(指向共享内存的第一个字节),使用p操控共享内存。 - shmat使用
p=shmat(shm_id,NULL,0);//让本进程链接到共享内存会得到一个共享内存的首地址p,可以直接通过指针p去操控共享内存。 - 参数
shmaddr:指定连接的地址
shmflg:两个可能取值SHM_RND和SHM_RDONLY
shmaddr和shmflg的组合关系 | 共享内存最终地址 |
---|---|
shmaddr为NULL,不管shmflg | 核心自动选择一个地址 |
shmaddr不为NULL且shmflg无SHM_RND标记 | 以shmaddr为连接地址 |
shmaddr不为NULL且shmflg设置了SHM_RND标记 | 连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA) |
shmflg=SHM_RDONLY | 表示连接操作用来只读共享内存 |
[3]shmdt:将共享内存段与当前进程脱离__int shmdt(const void *shmaddr);
参数shmaddr: 由shmat所返回的指针
注意:将共享内存段与当前进程脱离不等于删除共享内存段
[4]shmctl:控制共享内存__int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数cmd:
- IPC_STAT:获取shmid_ds结构中的值
- IPC_SET:设置shmid_ds结构中的值
- IPC_RMID:删除共享内存
IPC_RMID:共享内存的删除[难点]
- 如果共享内存被别的程序占用,连接数/引用计数不为0,则删除共享内存不会立马被删除====>删除后,会出现一个现象—共享内存key值变成了0,引用计数减1—且此时的共享内存已经不能被其他[新shmat]的进程读取了(重启一个进程重新shmat的时候由于key已经变为0,所以新开的进程是不能再继续读取共享内存的数据的);只能被在删除之前就[已经shmat]的进程读取。
- 只有当连接共享内存的所有进程都死掉,Linux内核才会删除共享内存
总结:是否能直接删除共享内存?
——>关键是看在删除以后有无进程链接到该块内存<==>等同于shmctl+shmdt删除之前有多少进程已经执行了shmat。
4.示例代码
代码功能介绍:
- 子进程向shm中写数据
- 父进程从shm中读取子进程向shm写入的数据
typedef struct student{
int age;
char name[10];
}student;
int main()
{
key_t key=ftok("/home/gjw/tmp",'a');
int shm_id=shmget(key,sizeof(int)*100,0664|IPC_CREAT);
pid_t pid=fork();
if(pid>0)
{
}
else if(pid==0)
{
void* ptr=shmat(shm_id,NULL,0);
struct student* stu=(struct student*)ptr;
stu->age=24;
strcpy(stu->name,"guojiawei");
shmdt(ptr);
exit(0);
}
sleep(1);
wait(NULL);
void* ptr=shmat(shm_id,NULL,0);
printf("age=%d, name=%s\n",((student*)ptr)->age,((student*)ptr)->name);
shmdt(ptr);
return 0;
}