Linux——详解共享内存shared memory

这篇具有很好参考价值的文章主要介绍了Linux——详解共享内存shared memory。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一.共享内存介绍

(一).什么是共享内存

(二).共享内存优点

(三).共享内存缺点

二.共享内存使用

(一).创建—shmget

①key

②size

③shmflg

④返回值

(二).连接—shmat

(三).分离—shmdt

(四).销毁—shmctl

(五).查看—ipcs

(六).删除—ipcrm

(七).读取与写入 

三.共享内存与访问控制

(一).添加访问控制

(二).可能的陷阱


一.共享内存介绍

(一).什么是共享内存

共享内存本质上就是内存中的一块区域,用于进程间通信使用。该内存空间由操作系统分配与管理。与文件系统类似的是,操作系统在管理共享内存时,不仅仅有内存数据块,同时还会创建相应结构体来记录该共享内存属性,以便于管理。

因此,共享内存不只有一份,可以根据需求申请多个。

进程之间进行通信的时候,会获取 到共享内存的地址,写端进程写入数据,读端进程通过直接访问内存完成数据读取。

(二).共享内存优点

相比于管道而言,共享内存不仅能够用于非父子进程之间的通信,而且访问数据的速度也比管道要快。这得益于通信直接访问内存,而管道则需要先通过操作系统访问文件再获得内存数据。

(三).共享内存缺点

用于进程间通信时,共享内存本身不支持阻塞等待操作。这是因为当读端读取数据后,数据并不会在内存中清空。因此读端和写端可以同时访问内存空间,即全双工。因为共享内存本质是进程直接访问内存,无法主动停止读取,如果读端不加以限制,那么将持续读取数据。同理,写端也会持续写入数据。换句话说,共享内存本身没有访问控制。 

二.共享内存使用

(一).创建—shmget

想要使用共享内存首先要建立共享内存。

Linux——详解共享内存shared memory

①key

shmget会根据key值创建一个共享内存,因此当创建多个共享内存时,每一个key值要独一无二。

获得key值可以使用库函数ftok专门获取一个独一无二的key_t类型值。

Linux——详解共享内存shared memory

参数pathname为路径,必须是真实存在且可以访问的路径。

参数proj_id是int类型数字,且必须传入非零值。

成功返回key_t值,失败返回-1。

Linux——详解共享内存shared memory

ftok函数内部会根据路径和proj_id通过算法生成一个独一无二的key_t返回值。

多进程通信时,需要通信双方使用同一个key值,因此双方使用的ftok参数应该一致。 

②size

该参数用于确定共享内存大小。

一般而言是4096的整数倍,因为内存的块的大小就是4KB即4096B。因此即便我们需要的空间大小不是块大小的整数倍,操作系统实际上也还是分配块的倍数个。但在使用时,那些超过size大小的多余分配空间不能访问。  

③shmflg

 该参数用于确定共享内存属性。

使用上为:标志位 | 内存权限

标志位参数有两种:IPC_CREAT、IPC_EXCL

常用使用方式有两种:

方式 含义
shmget(..., IPC_CREAT | 权限) 创建失败不报错返回已有shmid
shmget(..., IPC_CREAT | IPC_EXCL | 权限) 创建失败报错返回-1

值得注意PC_EXCL无法单独使用。

通常情况下在多进程通信时,创建方使用IPC_CREAT | IPC_EXCL,接收方使用0即可。

④返回值

返回值为int类型,称为shmid。每一个共享内存都会有一个shmid,用于连接与分离时传递参数。 

(二).连接—shmat

创建共享内存后还不能直接使用,需要找到内存地址后才能使用,即连接。 

Linux——详解共享内存shared memory

 shmid即shmget返回值。

shmaddr用于确定将共享内存挂在进程虚拟地址哪个位置,一般填nullptr即可代表让内核自己确定位置。

shmflg用于确定挂接方式,一般填0

连接成功返回共享内存在进程中的起始地址,失败返回-1。 

(三).分离—shmdt

当使用完毕后,需要分离挂接的共享内存。

Linux——详解共享内存shared memory

 shmaddr与shmat的相同,为共享内存在进程中地址位置,一般填nullptr。

分离成功返回0,失败返回-1。 

(四).销毁—shmctl

Linux——详解共享内存shared memory

该接口本身用于控制共享内存,可用于销毁。 

shmid不再介绍,cmd传入IPC_RMID,buf传nullptr。 

成功返回0,失败返回-1。 

(五).查看—ipcs

该指令为系统指令。

使用时可以查看当前全部共享内存。

ipcs -m 

(六).删除—ipcrm

通过指定共享内存shmid,进行删除。

ipcrm -m [shmid] 

Linux——详解共享内存shared memory 

(七).读取与写入 

调用shmat后会返回一个地址,读端直接读取该地址数据,写端直接向该地址写入即可。

//读端, 将共享内存数据读取到文件,此处为显示器文件
char* p = (char*)shmat(...);
write(1, p, sizeof p);
//写端,将文件中数据写入共享内存,此处为键盘文件
char* p = (char*)shmat(...);
read(0, p, 4096);

 

三.共享内存与访问控制

(一).添加访问控制

通过博客第一部分我们知道,共享内存不支持访问控制,那么我们可不可以添加访问控制给共享内存呢——完全可以。

方式是借用命名管道的访问控制,即阻塞。 

首先我们有如下代码,该代码是读端一直读取写端数据,直到写端输入quit为止。

//写端
int main()
{
  key_t key = ftok(".", 131);
  int shmid = shmget(key, 4096, IPC_CREAT|0660);//获取shmid
  char* p = (char*)shmat(shmid, nullptr, 0);//连接
  while(1){
    ssize_t s = read(0, p, 4096);//写入shm
    p[s - 1] = 0;
    assert(s > 0);
    (void)s;
  }
  shmdt(p);//分离
  return 0;
}
//读端
int main()
{
  key_t key = ftok(".", 131);
  int shmid = shmget(key, 4096, IPC_CREAT|IPC_EXCL|0660);//创建
  char* p = (char*)shmat(shmid, nullptr, 0);//连接
  while(1){
    assert(p != nullptr);
    if(strcmp(p, "quit") == 0)break;
    printf("%s\n", p);//读取shm中数据
    sleep(1);
  }
  shmdt(p);//分离
  shmctl(shmid, IPC_RMID, nullptr);//销毁
  return 0;
}

 但是因为共享内存无法访问控制,读端会一直读取数据,即便我们添加sleep函数也不能从根本解决问题。

解决方式是,在读端和写端分别加上管道的读端和写端。因为我们知道管道读端在读取到来自写端的数据前会阻塞,因此,将管道读端放在共享内存读端之前,将管道写端放在共享内存写端之后。

这样一来,当shm写端写入数据后会触发管道写端写数据,当管道写端写入数据后,管道读端才会停止阻塞,进而执行shm读端。

图例如下:

Linux——详解共享内存shared memory
代码如下: 

//写端
int main()
{
  key_t key = ftok(".", 131);
  int shmid = shmget(key, 4096, IPC_CREAT|0660);//获取shmid
  char* p = (char*)shmat(shmid, nullptr, 0);//连接
  int fd = open(..., O_WRONLY);//打开命名管道
  while(1){
    ssize_t s = read(0, p, 4096);//写入shm
    p[s - 1] = 0;
    assert(s > 0);
    (void)s;
    char i[4] = { 0 };
    write(fd, i, sizeof i);//写入管道
  }
  shmdt(p);//分离
  close(fd);
  return 0;
}
//读端
int main()
{
  int i = mkfifo(PATH_FIFO, 0660);//创建管道
  assert(i >= 0);
  key_t key = ftok(".", 131);
  int shmid = shmget(key, 4096, IPC_CREAT|IPC_EXCL|0660);//创建
  char* p = (char*)shmat(shmid, nullptr, 0);//连接shm
  int fd = open(..., O_RDONLY);//连接管道
  while(1){
    char buf[4];
    read(fd, buf, sizeof buf);//管道等待读取,阻塞
    assert(p != nullptr);
    if(strcmp(p, "quit") == 0)break;
    printf("%s\n", p);//读取shm中数据
    sleep(1);
  }
  shmdt(p);//分离
  shmctl(shmid, IPC_RMID, nullptr);//销毁
  close(fd);
  return 0;
}

(二).可能的陷阱

在添加访问控制时,会有一个可能的陷阱,就是命名管道可不可以在创建shm之前打开(open)呢?

不可以,因为打开管道要求读端和写端同时打开才能继续,否则就会阻塞。

如果阻塞的是写端还好,当读端创建完shm后写端创建失败返回shmid,但是如果阻塞的是读端,那么写端创建shm后,读端创建时因为加上IPC_EXCL的缘故,失败返回-1,之后shmat也失败返回nullptr,进而读端获取到的地址是空。

简单模块注意封装,复杂模块注意分层——未名


如有错误,敬请斧正文章来源地址https://www.toymoban.com/news/detail-414877.html

到了这里,关于Linux——详解共享内存shared memory的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 进程间通信--共享内存详解【Linux】

    本文详细讲解了共享内存的原理和使用,并且通过实例代码角度来深度理解共享内存,下面就让我们开始吧。 数据传输:一个进程需要将它的数据发送给另一个进程 资源共享:多个进程之间共享同样的资源。 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(

    2024年02月02日
    浏览(30)
  • CUDA:矩阵乘法的实现(Share Memory)

    本文参加2022CUDA on Platform线上训练营学习笔记 矩阵相乘是线性代数的基础,简单来解释就是A矩阵的行与B矩阵所在列相乘之和的结果,CPU端的代码可以采用模拟思想非常好编写, 相信聪明的你一定熟练掌握了矩阵相乘 ,这里就不做多的介绍了 CPU端的代码主要采用了模拟思想,

    2023年04月08日
    浏览(69)
  • Linux的NFS共享目录操作步骤

    首先准备两台Linux,一台服务器,一台客户机,IP地址可自行设置,两台防火墙都要关闭。 配置服务器IP地址:172.20.10.11 配置客户机IP地址:172.20.10.12 先关闭防火墙:systemctl stop filewalld.service 检查防火墙是否关闭:systemctl status filewalld  dead意思为关闭 服务器端 先检查有没有安

    2024年02月07日
    浏览(31)
  • Linux系统之文件共享目录设置方法

    1./data/soft的用户组为admin 2./data/soft目录能被admin组的成员读取、写入和访问,除了root用户外其余用户无此权限。 3.admin组用户有zhangsan/lisi/admin,kitty用户主组为kitty,属组为IT。 4.在/data/soft下创建的文件,其组所有权为admin组。 直接创建zhangsan/lisi/kitty/admin三个用户。 创建adm

    2024年02月06日
    浏览(37)
  • 在linux上挂载windows共享目录

    非root用户(普通用户)能够读写windows共享目录,比如查看文件、创建文件、修改文件、删除文件 挂载步骤 先在 Windows 下面共享需要挂载的目录 指定需要共享的文件目录:Downloads 右键》共享》网络文件和文件夹共享》共享…》选择要与其共享的用户》默认用户即可 右键》共

    2024年02月09日
    浏览(37)
  • Linux 内存模型(Memory: the flat, the discontiguous, and the sparse)

    计算机系统中的物理内存是一种宝贵的资源,因此人们付出了大量的努力来有效地管理它。由于现代系统上存储器体系结构的复杂性,这项任务变得更加困难。有几个抽象层处理如何布局物理内存的细节;其中一个简单地称为“内存模型”。内核中支持三个模型,但其中一个

    2024年02月14日
    浏览(30)
  • CUDA:矩阵转置的GPU实现(Share Memory)

    本文参加2022CUDA on Platform线上训练营学习笔记 欢迎各位 大犇 提意见 上图中将 m * n 的矩阵A通过矩阵转置变成了 n * m 的 A T ,简单来讲矩阵转置即为将原始矩阵的第一行转置为目标矩阵的第一列,以此类推, 相信基础扎实的你简单地看看CPU端的代码就能理解 定义一个名为 cpu_t

    2024年02月12日
    浏览(26)
  • 【Gradio-Windows-Linux】解决share=True无法创建共享链接,缺少frpc_windows_amd64_v0.2

    随着机器学习技术的快速发展,将训练好的模型部署为实际应用变得愈发重要。Gradio作为一个强大的开源库,为我们提供了一个简单而高效的解决方案。然而,近期在使用 share=True 时可能会遇到一些问题,具体来说,问题可能出现在缺少 frpc_windows_amd64_v0.2 文件的情况下,导致

    2024年02月05日
    浏览(41)
  • (26)Linux 进程通信之共享内存(共享储存空间)

    共享内存是System V版本的最后一个进程间通信方式。 共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内

    2024年01月16日
    浏览(31)
  • 【Linux】进程通信 — 共享内存

    上一章我们由进程通信,引入并讲述了管道,匿名管道和命名管道和匿名管道。本章我们将继续讲解进程通信的另一种方式,通过共享内存的方式来进行进程间的通信。还要学习几个系统调用接口,并用代码实现两个进程通过共享内存来进行通信。目标已经确定,接下来就要

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包