Linux系统编程-进程间通信(共享内存)

简介: 共享内存也是进程间(进程间不需要有继承关系)通信的一种常用手段。一般OS通过内存映射与页交换技术,使进程的内存空间映射到不同的物理内存,这样能保证每个进程运行的独立性,不至于受其它进程的影响。但可以通过共享内存的方式,使不同进程的虚拟内存映射到同一块物理内存,一个进程往这块物理内存中更新的数据,另外的进程可以立即看到这块物理内存中修改的内容。

前面陆续介绍了标准管道流、无名管道、命名管道、mmap内存映射,这篇文章介绍共享内存段。

1. 共享内存机制(shmget)

共享内存也是进程间(进程间不需要有继承关系)通信的一种常用手段。一般OS通过内存映射与页交换技术,使进程的内存空间映射到不同的物理内存,这样能保证每个进程运行的独立性,不至于受其它进程的影响。但可以通过共享内存的方式,使不同进程的虚拟内存映射到同一块物理内存,一个进程往这块物理内存中更新的数据,另外的进程可以立即看到这块物理内存中修改的内容。

内存映射和共享内存的区别:

mmap内存映射:跟普通文件的读写相比,加快对文件/设备的访问速度。
shmget共享内存:多进程间进行通信。

原理及实现:

system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共享内存区域中,所有需要访问该共享区域的进程都要把该共享区域映射到本进程的地址空间中去。这样一个使用共享内存的进程可以将信息写入该空间,而另一个使用共享内存的进程又可以通过简单的内存读操作获取刚才写入的信息,使得两个不同进程之间进行了一次信息交换,从而实现进程间的通信。共享内存允许一个或多个进程通过同时出现在它们的虚拟地址空间的内存进行通信,而这块虚拟内存的页面被每个共享进程的页表条目所引用,同时并不需要在所有进程的虚拟内存都有相同的地址。进程对象对于共享内存的访问通过key(键)来控制,同时通过key进行访问权限的检查。

2. 共享内存机制相关函数接口介绍

2.1 ftok函数

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

函数功能: 用于创建一个关键字,可以用该关键字关联一个共享内存段。
参数介绍:
(1) pathname:全路径文件名,并且该文件必须可访问。
(2) proj_id:通常传入一非0字符。通过pathname和proj_id组合可以创建唯一的key(对任何进程都是唯一且相同的)。
返回值:
如果调用成功,返回一关键字,否则返回-1。

2.2 shmge函数

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);

shmget 函数用于创建或打开一共享内存段,该内存段由函数的第一个参数标识。函数成功则返回一个该共享内存段的唯一标识号(唯一的标识了这个共享内存段),对任何进程都是唯一且相同的。

参数介绍
(1) key是一个与共享内存段相关联的关键字,如果事先已经存在一个与指定关键字关联的共享内存段,则直接返回该内存段的标识。key的值既可以用ftok函数产生,也可以是IPC_RPIVATE(用于创建一个只属于创建进程的共享内存,主要用于父子通信),表示总是创建新的共享内存段。
(2) size指定共享内存段的大小,以字节为单位。
(3) shmflg是一掩码合成值,可以是访问权限值与(IPC_CREAT或IPC_EXCL)的合成。IPC_CREAT表示如果不存在该内存段,则创建它。IPC_EXCL表示如果该内存段存在,则函数返回失败结果(-1)。

返回值

如果调用成功,返回内存段标识,否则返回-1。

2.3 shmat函数

函数shmat将共享内存段映射到进程空间的某一地址。

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);

注意: 只有管理员用户权限才可以获取内存地址

参数
(1) shmid 是共享内存段的标识通常应该是shmget的成功返回值。
(2) shmaddr指定的是共享内存连接到当前进程中的地址位置。通常是NULL,表示让系统来选择共享内存出现的地址。
(3) shmflg是一组位标识,通常为0即可。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式。

返回值
如果调用成功,返回映射后的进程空间的首地址,否则返回(void*)-1。

2.4 shmdt函数

shmdt用于将共享内存段与进程空间分离,与shmat函数相反。用于关闭共享内存段。

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);

参数
shmaddr通常为shmat的成功返回值。
返回值
成功返回0,失败时返回-1。
注意:只是将共享内存分离,并没有没删除它,只是使得该共享内存对当前进程不再可用。

2.5 shmctl函数

函数shmctl是共享内存的控制函数,可以用来删除共享内存段。

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数:

(1)shmid:共享内存段标识 通常应该是shmget的成功返回值

(2)cmd:对共享内存段的操作方式

IPC_STAT 得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET 改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID 删除这片共享内存

可选为IPC_STAT,IPC_SET,IPC_RMID。通常为IPC_RMID,表示删除共享内存段。

(3)buf:表示共享内存段的信息结构体数据,通常为NULL。

例如: shmctl(kshareMem,IPC_RMID,NULL)表示删除共享内存段kHareMem

3. 案例: 基本用法示例1

3.1 创建内存段写数据示例

下面代码使用/work/1.dat的文件属性获取key,作为内存标识符;再创建共享内存段,映射内存地址,然后向内存空间写入数据"hello world",再取消映射。这时候其他进程就可以访问这个内存段读取里面的数据。

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int main()
{
    key_t key = ftok("/work/1.dat",1);                //1. 写入端先用ftok函数获得key
    int shmid = shmget(key,4096,IPC_CREAT);     //2. 写入端用shmget函数创建共享内存段
    printf("key = %d shmid = %d\n", key, shmid);
    char *p = (char *)shmat(shmid, NULL, 0);     //3. 获得共享内存段的首地址
    memset(p, 0, 4096);                       //  清除内存空间
    memcpy(p, "hello world", 4096);                //4. 往共享内存段中写入内容
    shmdt(p);                               //5. 关闭共享内存段
    return 0;
}

3.2 打开内存段读取示例

下面代码用来访问,上面写端代码创建的共享内存段里的数据,流程一样。shmget函数如果判断出共享内存段已经存在,就不会再重复创建(依靠key作为标识符判断的);接着再映射空间地址,读取内存里的数据,打印出hello world,最后再销毁内存空间。

#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
int main()
{
    key_t key = ftok("/work/1.dat",1);
    int shmid = shmget(key,4096,IPC_CREAT);
    printf("key = %d shmid = %d\n", key, shmid);
    char *p = (char *)shmat(shmid, NULL, 0);
    printf("receive the data:%s\n",p);             //4. 读取共享内存段中的内容
    shmctl(shmid, IPC_RMID, 0);             //5. 删除共享内存段
//不删除内存空间,数据会一直存在的
    return 0;
}

4. 案例: 基本用法示例2

上面例子代码是通过获取文件的属性得到唯一的key,实际上也可以自己指定key,只要保证唯一性即可。

4.1 创建内存写数据示例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/shm.h>

int main(int argc,char **argv)
{
    /*1. 创建共享内存段*/
    int shmid=shmget(123456,4096,IPC_CREAT);
    /*2. 映射共享内存到进程空间*/
    unsigned char *p;
    p=shmat(shmid,NULL,0);
    /*3. 对共享内存实现读写*/
    strcpy(p,"Linux下进程间通信共享内存学习");
    /*4. 取消映射*/
    shmdt(p);
    return 0;
}

4.2 打开内存读数据示例

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/shm.h>

int main(int argc,char **argv)
{
    /*1. 创建共享内存段*/
    int shmid=shmget(123456,4096,IPC_CREAT);
    /*2. 映射共享内存到进程空间*/
    unsigned char *p;
    p=shmat(shmid,NULL,0);
    /*3. 对共享内存实现读写*/
    printf("p=%s\n",p);
    /*4. 取消映射*/
    shmdt(p);
    /*5. 释放共享内存空间*/
    shmctl(shmid,IPC_RMID,NULL);
    return 0;
}
目录
相关文章
|
22天前
|
存储 缓存 监控
Linux缓存管理:如何安全地清理系统缓存
在Linux系统中,内存管理至关重要。本文详细介绍了如何安全地清理系统缓存,特别是通过使用`/proc/sys/vm/drop_caches`接口。内容包括清理缓存的原因、步骤、注意事项和最佳实践,帮助你在必要时优化系统性能。
159 78
|
21天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
89 13
|
22天前
|
Ubuntu Linux C++
Win10系统上直接使用linux子系统教程(仅需五步!超简单,快速上手)
本文介绍了如何在Windows 10上安装并使用Linux子系统。首先,通过应用商店安装Windows Terminal和Linux系统(如Ubuntu)。接着,在控制面板中启用“适用于Linux的Windows子系统”并重启电脑。最后,在Windows Terminal中选择安装的Linux系统即可开始使用。文中还提供了注意事项和进一步配置的链接。
40 0
|
2月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
162 8
|
2月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
640 6
|
2月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
111 3
|
2月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
92 2
|
1月前
|
Linux Shell
Linux 10 个“who”命令示例
Linux 10 个“who”命令示例
61 14
Linux 10 个“who”命令示例
|
12天前
|
Linux
linux查看目录下的文件夹命令,find查找某个目录,但是不包括这个目录本身?
通过本文的介绍,您应该对如何在 Linux 系统中查看目录下的文件夹以及使用 `find` 命令查找特定目录内容并排除该目录本身有了清晰的理解。掌握这些命令和技巧,可以大大提高日常文件管理和查找操作的效率。 在实际应用中,灵活使用这些命令和参数,可以帮助您快速定位和管理文件和目录,满足各种复杂的文件系统操作需求。
38 8
|
22天前
|
Ubuntu Linux
Linux 各发行版安装 ping 命令指南
如何在不同 Linux 发行版(Ubuntu/Debian、CentOS/RHEL/Fedora、Arch Linux、openSUSE、Alpine Linux)上安装 `ping` 命令,详细列出各发行版的安装步骤和验证方法,帮助系统管理员和网络工程师快速排查网络问题。
116 20
下一篇
开通oss服务