共享内存(Shared Memory)就是允许两个或多个进程访问同一个内存空间,是在多进程通信的最高效的方式。
操作系统将不同进程之间共享内存安排为同一段物理内存,进程可以将共享内存连接到它们自己的地址空间中,如果某个进程修改了共享内存中的数据,其它的进程读到的数据也将会改变。由于共享内存会成为进程用户空间的一部分,所有这种通信方式不需要内核介入。
共享内存并未提供锁机制,也就是说,在某一个进程对共享内存的进行读写的时候,不会阻止其它的进程对它的读写,可能会出现数据的错乱。
1、必备头文件
#include#include
2、shmget() 获取或创建共享内存
// 获取或者创建共享内存 int shmget(key_t key, size_t size, int shmflg); - key是共享内存的键值,是一个整数,是共享内存在系统中的编号,不同共享内存的编号不同。一般使用十六进制。 - size表示待创建共享内存的大小,以字节为单位 - shmflg表示共享内存的访问权限,与文件的权限一样, 0666 | IPC_CREAT 表示全部用户对它可读写 - 返回值:返回共享内存标识
3、shmat() 把共享内存连接到当前进程的地址空间
void *shmat(int shm_id, const void *shm_addr, int shmflg); - shm_id表示由 shmget函数返回的 共享内存的标识号 - shm_addr指定共享内存连接到当前进程中的地址位置,通常为 NULL,表示让系统来选择共享内存的地址。 - shm_flg是一组标志位,通常为0 - 返回值: 调用成功:返回一个指向共享内存第一个字节的指针 调用失败:返回 -1
4、shmdt() 将共享内存从当前进程中分离,相当于 shmat()函数的反操作
int shmdt(const void *shmaddr); - shmaddr是 shmat函数 返回的地址 - 返回值: 调用成功:返回 0 调用失败:返回 -1
5、shmctl() 删除共享内存
int shmctl(int shm_id, int command, struct shmid_ds *buf); - shm_id是共享内存的标识号 - command 填写 IPC_RMID - buf 填写 0 - 返回值: 调用成功:返回 0 调用失败:返回 -1使用步骤
- 调用 shmget() 函数创建一个新共享内存段或取得一个现有的共享内存段的标识号。返回后续可调用的需要用到的共享内存标识符。
- 在进程中使用 shmat() 函数附上共享内存段,即让该共享内存段成为调用进程的虚拟内存中的一部分(进程绑定共享内存段)
- 使用 shmat() 返回的内存地址指针,就可以在程序中对该共享内存段进行操作(写操作/读操作)。
- 调用 shmdt() 函数,让进程和共享内存段分离,进程无法再操作共享内存了。(只是分离,共享内存依然存在)
- 调用 shmctl() 函数,删除共享内存段,只有当与该共享内存段绑定好的进程都分离后,才会销毁,只有一个进程需要执行这一步。
// write_shm.c #include#include #include #include #include int main() { int shmid; // 共享内存标识符 // 创建共享内存,键值为0x5005,共1024字节。 if ( (shmid = shmget((key_t)0x5005, 1024, 0666 | IPC_CREAT)) == -1) { printf("shmat(0x5005) failedn"); return -1; } char *ptext = NULL; // 用于指向共享内存的指针 // 将共享内存连接到当前进程的地址空间,由ptext指针指向它 ptext = (char *)shmat(shmid, NULL, 0); // 操作本程序的ptext指针,就是操作共享内存 char *str = "Hello world!"; memcpy(ptext, str, strlen(str)); // 把共享内存从当前进程中分离 shmdt(ptext); return 0; }
// read_shm.c
int main()
{
int shmid; // 共享内存标识符
// 创建共享内存,键值为0x5005,共1024字节。
if ( (shmid = shmget((key_t)0x5005, 1024, 0666 | IPC_CREAT)) == -1)
{
printf("shmat(0x5005) failedn");
return -1;
}
char *ptext = NULL; // 用于指向共享内存的指针
// 将共享内存连接到当前进程的地址空间,由ptext指针指向它
ptext = (char *)shmat(shmid, NULL, 0);
// 操作本程序的ptext指针,就是操作共享内存
printf("%sn", ptext);
// 把共享内存从当前进程中分离
shmdt(ptext);
// 删除共享内存
if (shmctl(shmid, IPC_RMID, 0) == -1)
{
printf("shmctl(0x5005) failedn");
return -1;
}
}
read_shm.c的输出结果:
Hello world!
可以看出,write_shm.c 申请共享内存,并写入数据,read_shm获取共享内存标识号,并绑定进程,读取该共享内存中的数据。
查看共享内存ipcs -m # 查看现有的所有共享内存段 ipcrm -m shmid # 根据共享内存段的标识号,删除共享内存



