Linux进程通信 | 共享内存
一、共享内存是什么
在Linux系统中,共享内存是一种IPC(进程间通信)方式,它可以让多个进程在物理内存中共享一段内存区域。
这种共享内存区域被映射到多个进程的虚拟地址空间中,使得多个进程可以直接访问同一段物理内存区域中的数据,从而实现进程间的高速数据交换和通信。
二、共享内存的原理
共享内存基于内核的支持。在共享内存中,内核维护了一块物理内存区域,并将其映射到多个进程的虚拟地址空间中。每个进程都可以使用指针来访问共享内存区域中的数据,就像它们访问自己的内存一样。

三、共享内存的使用方法
相关函数介绍
shmget函数
int shmget(key_t key, size_t size, int shmflg);
用于创建或打开一个共享内存区段,具体参数如下:
| 参数 | 类型 | 说明 |
|---|---|---|
key |
key_t |
共享内存区段的关键字,用于在多个进程间标识同一个共享内存区段。 |
size |
size_t |
共享内存区段的大小,以字节为单位。 |
shmflg |
int |
共享内存区段的访问权限和行为属性。 |
函数返回值为共享内存区段的标识符 shmid,用于标识已创建或已打开的共享内存区段。
shmat函数
void *shmat(int shmid, const void *shmaddr, int shmflg);
用于将共享内存区段连接到当前进程的地址空间,具体参数如下:
| 参数 | 类型 | 说明 |
|---|---|---|
shmid |
int |
共享内存区段的标识符,用于标识已创建或已打开的共享内存区段。 |
shmaddr |
const void* |
共享内存区段连接到当前进程地址空间的起始地址,如果为 NULL,则由系统自动选择一个地址。 |
shmflg |
int |
标志参数,指定共享内存区段的访问权限和行为属性。 |
函数返回值为共享内存区段连接到当前进程地址空间的起始地址,即指向共享内存区段的指针。
shmdt函数
int shmdt(const void *shmaddr);
用于断开进程与共享内存区段的连接,具体参数如下:
| 参数 | 类型 | 说明 |
|---|---|---|
shmaddr |
const void* |
共享内存区段连接到当前进程地址空间的起始地址。 |
函数返回值为 0 表示成功,-1 表示失败。
shmctl函数
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
用于控制共享内存区段的行为,如删除、获取、设置共享内存区段的属性等,具体参数如下:
| 参数 | 类型 | 说明 |
|---|---|---|
shmid |
int |
共享内存区段的标识符,用于标识已创建或已打开的共享内存区段。 |
cmd |
int |
控制命令,指定对共享内存区段的操作类型。 |
buf |
struct shmid_ds* |
指向共享内存区段属性结构体的指针,用于获取或设置共享内存区段的属性。 |
常用的cmd参数包括:
- IPC_STAT:获取共享内存的状态信息,并将该信息存储在
buf参数指向的结构体中。 - IPC_SET:设置共享内存的状态信息,
buf参数指向要设置的新值。 - IPC_RMID:删除共享内存。
函数返回值为操作成功返回 0,失败返回 -1。
实例演示
以下是一个示例代码,其中一个程序用于写入共享内存,另一个程序用于读取共享内存。
写入程序
/* write.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024
int main()
{
int shmid;
char *shmaddr;
char write_buf[SHM_SIZE];
// 创建共享内存段
shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
exit(EXIT_FAILURE);
}
// 将共享内存段连接到当前进程
shmaddr = (char*)shmat(shmid, 0, 0);
if (shmaddr == (void*)-1) {
perror("shmat failed");
exit(EXIT_FAILURE);
}
// 从标准输入读取数据并将其写入共享内存
while(1) {
fgets(write_buf, SHM_SIZE, stdin);
strncpy(shmaddr, write_buf, SHM_SIZE);
if (strncmp(write_buf, "exit", 4) == 0) {
break;
}
}
// 断开共享内存连接
if (shmdt(shmaddr) == -1) {
perror("shmdt failed");
exit(EXIT_FAILURE);
}
// 删除共享内存段
if (shmctl(shmid, IPC_RMID, 0) == -1) {
perror("shmctl failed");
exit(EXIT_FAILURE);
}
printf("write exit\n");
return 0;
}
读取程序
/* read.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <string.h>
#define SHM_SIZE 1024
int main()
{
int shmid;
char *shmaddr;
char read_buf[SHM_SIZE];
// 获取共享内存段
shmid = shmget((key_t)1234, SHM_SIZE, 0666|IPC_CREAT);
if (shmid == -1) {
perror("shmget failed");
exit(EXIT_FAILURE);
}
// 将共享内存段连接到当前进程
shmaddr = (char*)shmat(shmid, 0, 0);
if (shmaddr == (void*)-1) {
perror("shmat failed");
exit(EXIT_FAILURE);
}
// 从共享内存读取数据并输出到标准输出
while(1) {
strncpy(read_buf, shmaddr, SHM_SIZE);
printf("Received message: %s\n", read_buf);
if (strncmp(read_buf, "exit", 4) == 0) {
printf("Received exit\n");
break;
}
sleep(1);
}
// 断开共享内存连接
if (shmdt(shmaddr) == -1) {
perror("shmdt failed");
exit(EXIT_FAILURE);
}
printf("read exit\n");
return 0;
}
- 编译这两个程序
gcc -o write write.c
gcc -o read read.c
在一个终端窗口中运行write, 输入消息,在另一个终端窗口中运行read,查看消息。
要退出程序,则在运行write的终端窗口中键入"exit",效果如下:

四、 共享内存的注意事项
- 使用共享内存需要注意以下几点:
- 同步问题:由于多个进程可以同时访问共享内存,因此必须要使用同步机制来保证数据的一致性和正确性。
- 内存泄漏:如果一个进程崩溃或者没有及时解除共享内存映射,就有可能导致内存泄漏的问题。
- 安全问题:共享内存是多个进程共享的,因此必须要注意数据的安全性和隐私性,避免敏感数据泄露。
五、 共享内存的使用技巧
- 以下是一些共享内存的使用技巧:
- 分配内存时使用
shmget()系统调用中的IPC_PRIVATE标记,可以确保共享内存的键值在系统中是唯一的,避免冲突和安全问题。 - 在读写共享内存之前,使用信号量或互斥锁等同步机制来保证数据的一致性和正确性。
- 在使用共享内存时,可以将共享内存区域按照固定大小进行分块,避免多个进程同时访问同一块内存区域的冲突。
小结
共享内存是一种高效、灵活、方便的进程间通信方式,可以用于在多个进程之间共享大量数据。
使用共享内存需要注意同步、安全和内存泄漏等问题,可以使用信号量、互斥锁等同步机制来保证数据的正确性。
以上,如果觉得对你有帮助,点个赞再走吧,这样@知微之见也有更新下去的动力!
也欢迎私信我,一起交流!
Linux进程通信 | 共享内存的更多相关文章
- Linux学习笔记(14)-进程通信|共享内存
在Linux中,共享内存是允许两个不相关的进程访问同一个逻辑内存的进程间通信方法,是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式. 不同进程之间共享的内存通常安排为同一段物理内存.进程可 ...
- Windows进程通信 -- 共享内存(1)
共享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 W ...
- Windows进程通信 -- 共享内存
享内存的方式原理就是将一份物理内存映射到不同进程各自的虚拟地址空间上,这样每个进程都可以读取同一份数据,从而实现进程通信.因为是通过内存操作实现通信,因此是一种最高效的数据交换方法. 共享内存在 Wi ...
- Windows进程通信-共享内存空间
三个模块 1,game.exe,三个方法,控制台输入指令('A','B','R')分别控制三个方法的调用: 2,WGDll.dll,要注入到game进程中的dll文件: 3,myconsole.exe ...
- linux 进程间共享内存示例
写入端: #include <iostream> #include <unistd.h> #include <stdlib.h> #include <stdi ...
- 撸代码--linux进程通信(基于共享内存)
1.实现亲缘关系进程的通信,父写子读 思路分析:1)首先我们须要创建一个共享内存. 2)父子进程的创建要用到fork函数.fork函数创建后,两个进程分别独立的执行. 3)父进程完毕写的内容.同一时候 ...
- linux 进程通信之 共享内存
共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...
- linux 两个进程通过 共享内存 通信例子
例子1:两个进程通过共享内存通信,一个进程向共享内存中写入数据,另一个进程从共享内存中读出数据 文件1 创建进程1,实现功能,打印共享内存中的数据 #include <stdio.h> # ...
- linux进程通信之共享内存
共享内存同意两个或多个进程共享一给定的存储区,由于数据不须要来回复制,所以是最快的一种进程间通信机制.共享内存能够通过mmap()映射普通文件(特殊情况下还能够採用匿名映射)机制实现,也能够通过系统V ...
- Windows进程间共享内存通信实例
Windows进程间共享内存通信实例 抄抄补补整出来 采用内存映射文件实现WIN32进程间的通讯:Windows中的内存映射文件的机制为我们高效地操作文件提供了一种途径,它允许我们在WIN32进程中保 ...
随机推荐
- Pgsql之查询一段时间内的所有日期
前几天干活儿的时候,项目中有这么个需求,需要用pgsql查询两个日期间的所有日期,包括年月日,下面贴代码: 1 select date(t) as day 2 from 3 generate_seri ...
- 9 时序数据库M3DB架构与原理
一.M3DB介绍 M3DB是Uber开源的一款分布式时序数据库,已在Uber内部使用多年.M3DB有以下特性: 分布式的时序数据库,可以水平扩展存储. 支持Pormetheus的查询语言PromQL, ...
- Linux查看文件内容与处理文件
Linux查看文件内容与处理文件 目录 Linux查看文件内容与处理文件 查看文件内容 1.查看文件类型 2.查看整个文件 3.查看部分文件 处理文件 1.创建空文件 2.过滤文件内容 3.统计文件内 ...
- MySQL shell 备份数据库
MySQL shell 备份数据库 背景 之前使用 mysqldump 和 mysql source 的方式备份数据库非常缓慢 有时候要耗费非常长的时间 今天发现有一个可以快速备份数据库的 mysql ...
- Redis不同版本性能研究
Redis不同版本性能研究 背景 前期同事遇到了一个大key的慢查询. 前提条件是: 一个 60万key的环境里面. 有一个 260万元素的set类型的key 产品经常会进行 smember key ...
- [转帖]Fluentd 的优缺点
https://zhuanlan.zhihu.com/p/129375187 以前在不少场合浅度使用过 Fluentd,将日志汇聚到一个地方.它给我的大体印象是 简单且能解决问题 直到最近遇到一个 ...
- Walrus 0.5发布:重构交互流程,打造开箱即用的部署体验
开源应用管理平台 Walrus 0.5 已于近日正式发布! Walrus 0.4 引入了全新应用模型,极大程度减少了重复的配置工作,并为研发团队屏蔽了云原生及基础设施的复杂度.Walrus 0.5 在 ...
- 3.1 Windows驱动开发:内核远程堆分配与销毁
在开始学习内核内存读写篇之前,我们先来实现一个简单的内存分配销毁堆的功能,在内核空间内用户依然可以动态的申请与销毁一段可控的堆空间,一般而言内核中提供了ZwAllocateVirtualMemory这 ...
- 3.1 C/C++ 使用字符与指针
C/C++语言是一种通用的编程语言,具有高效.灵活和可移植等特点.C语言主要用于系统编程,如操作系统.编译器.数据库等:C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统.图形用户界面 ...
- Python 实现专属字典生成器
编写一个密码生成工具,这里我们使用弱密码与个性化数组组合形成一个定制字典,例如收集用户的姓名,昵称,QQ号手机号等资源,然后通过Python对搜集到的数据与弱密码进行结合,从而定制出属于某个人的专属密 ...