何为共享内存
共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
但要特别注意的是共享内存并未提供同步机制。也就是说,在第一个进程结束对共享内存的操作之前,并没有自动机制可以阻止第二个进程开始对它进行读取。所以通常需要使用其它的机制来同步对共享内存的访问,比如信号量。
共享内存机制
如图,再物理地址空间中开辟一块空间作为共享内存,然后PCB1和PCB2通过页表+MMU的机制将这块物理地址空间挂接到各自的虚拟地址空间,如此,就可以使这两个进程通过地址空间看到同一份公共资源:共享内存。原理就是如此简单,但底层实现还是很复杂的。
需要特别说明的是:
通过共享内存实现进程间通信是最快的!
为什么呢?对比其它的进程间通信机制,都是进程1将数据写到公共资源上,进程2去读,这里面就包含了两次拷贝,第一次将数据从用户空间拷贝到内核,第二次将数据从内核拷贝到用户空间。再来看共享内存机制:进程1将数据写到共享内存,然后无需任何拷贝,进程2可以直接访问到这部分数据,所以就节省了两次拷贝的时间。
函数原型
创建和获取共享内存:
size指定共享内存大小,最好设置为4096的整数倍,因为操作系统以页为基本单位来分配共享内存。
销毁:
cmd传IPC_RMID即可,buf设为NULL,不关心。
挂接与去挂接:
shmaddr可以设为你想映射的虚拟地址,但一般不自己指定,因为你不知道哪里合适,所以设为NULL即可。shmflg缺省为0.
举个栗子
server不断往共享内存中写数据,client来读。(同步问题暂未考虑)
comm.h
#pragma once #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #define _PATH_NAME_ "/tmp" #define _PROJ_ID_ 0x666 int create_shm(int size); int get_shm(); int destroy_shm(int shm_id); void * at(int shm_id); int dt(void *addr);
comm.c
#include "comm.h" #include <stdio.h> static int comm_shm(int size, int flag) { key_t key = ftok(_PATH_NAME_, _PROJ_ID_); if (key < 0) { perror("ftok"); return -2; } return shmget(key, size, flag); } int create_shm(int size) { int flag = IPC_CREAT | IPC_EXCL | 0644; return comm_shm(size, flag); } int get_shm() { int flag = IPC_CREAT; return comm_shm(0, flag); } int destroy_shm(int shm_id) { return shmctl(shm_id, IPC_RMID, NULL); } void * at(int shm_id) { return shmat(shm_id, NULL, 0); } int dt(void *addr) { return shmdt(addr); }
server.c
#include <stdio.h> #include <unistd.h> #include "comm.h" int main() { int shm_id = create_shm(4096); char *addr = (char *)at(shm_id); int i = 0; while (1) { addr[i] = 'A'; addr[i + 1] = 0; ++i; i %= 4096; sleep(1); } dt(addr); destroy_shm(shm_id); return 0; }
client.c#include <stdio.h> #include <unistd.h> #include "comm.h" int main() { int shm_id = get_shm(); char *addr = (char *)at(shm_id); int i = 0; while (1) { printf("%s\n", addr); sleep(1); } dt(addr); return 0; }
运行结果:
进程间通信之共享内存
最新推荐文章于 2023-06-29 12:18:53 发布