博客内容:共享内存
文章目录
- 一、认识共享内存结构
- 二、如何创建共享内存?
- 1.创建共享内存
- 2.关联进程,取消进程
- 3.释放共享内存
- 三、代码示例
- 总结
一、认识共享内存结构
共享内存
共享内存指 (shared memory)在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。
解释比较官方,对于进程来说就是PCB,内存描述符(mm_struct)、页表,还有内存之间的关系。简单的描述后就是以下这样的方式。对于内存描述符类似于文件描述符。共享内存是为了让不同的进程实现通信,就必须先让不同的进程来看见同一份资源
。
二、如何创建共享内存?
1.创建共享内存
使用共享内存需要知道这些接口,创建函数接口
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
共享内存是哪块,有多大,权限设置。第一个参数就是对于内存位置来表示内存的key。ftok函数就是采用路径和项目名来生成一个不易于冲突的一个key值。
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
第二个参数就是设置大小。对于后面第3个参数shmflg就是设置权限,权限和文件操作的权限采用的都是位图的数据结构来表示。
2.关联进程,取消进程
共享内存的创建完成后还需要让进程看见,需要将进程与内存关联在一起,摩天大厦也需要和自己挂钩才是自己的。所以就有函数shmat、shmdt。
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
分别实现对于进程的关联和去关联。关联同一块内需要同样的key才能看见同一块内存。shmat第二个参数一般设置为null,函数会自己找到合适的地址。函数使用时与C语言的malloc类似都需要进行内存的一个转换,shmdt去关联时函数需要传入的是空间地址。就是shmat的返回值。在shmat与shmat之间就是通信的内容。
3.释放共享内存
共享内存是一套类似于文件描述符的规则,它不会随着进程而销毁,它跟随的是OS。所以在使用完后还需要使用函数进行销毁内存空间。使用函数进行空间释放后对于需要传输的是shmid就是使用函数shmget后的返回值,第二个参数就是命令IPC_RMID
,第3个参数一般设置为null。
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
三、代码示例
创建一个共享内存,实现通信 “i am process A”
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 4096
int main()
{
key_t key = ftok(".", 'a');
int shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666);
char *shmaddr = (char *) shmat(shmid, NULL, 0);
pid_t pid = fork();
if (pid < 0) {
printf("Fork Error\n");
return -1;
} else if (pid == 0) { // 子进程
char *data = "i am process A";
memcpy(shmaddr, data, strlen(data));
} else { // 父进程
usleep(100000); // 等待子进程写入数据
printf("%s\n", shmaddr);
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, NULL);
}
return 0;
}
总结
需要注意的就是函数的返回值需要进行判断。在通信时使用是字节流通信。相关查询命令
ipcs -m//查询共享内存
ipcs -q//消息队列
ipcs -s //查看信号量对象
ipcrm -Q key :根据键值key,删除指定的消息对列
ipcrm -q id :根据ID,删除指定的消息对列
ipcrm -M key :根据键值key,删除指定的共享内存
ipcrm -m id :根据ID,删除指定的共享内存
ipcrm -S key :根据键值key,删除指定的信号量
ipcrm -s id :根据ID,删除指定的信号量