916-关于共享内存

2023-11-04 08:59
文章标签 共享内存 916

本文主要是介绍916-关于共享内存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

我们知道各进程之间是独立存在,互不影响的。有没有一种方式让这些进程之间产生联系呢?当然有!那就是共享内存。共享内存是进程间通信中最简单的方式之一。

站在进程的角度来说,共享内存就是可以同时被多个进程访问的内存。由于所有进程共享同一块内存,因此这种通信方式效率非常高。

为什么进程间的内存不是共享的吧?
举一个例子,假设有 2 个进程同时想让某一物理地址保存一个值,A 进程想让这个物理地址保存 1,B 进程想让这个物理地址保存 2。那么这个物理地址到底应该保存哪个值?所以,为了将每个进程隔离开,设计者就想到一个办法,操作系统会给每个进程分配一个虚拟地址。然后将不同进程的虚拟地址和不同内存的物理地址进行映射。

每次进程想要写入数据,先访问虚拟地址,然后内存再将这个地址转换成物理地址,这样不同进程运行的时候,写入的是不同物理地址,就不会有冲突了。这就是进程独享内存空间的原理。我下面给您画个图。实际中虚拟内存和物理内存都会被分成大小相等的页,然后进行映射。但是由于我们这次面试的重点不在此,图就简略一点,表明关系就好。
在这里插入图片描述
为什么要引入虚拟地址呢?运行过程中还得进行虚拟地址和物理地址进行转换。我看看物理内存有多大,直接把一段物理空间交给一个进程不好吗?然后这段空间不允许别的进程进行操作。这样不更省事?

1、操作系统是不希望一个普通的进程可以直接对物理地址写数据的。如果一个普通的进程可以随意的向物理地址中写数据。那么一个恶意进程一旦知道别的进程的物理地址,那不是很容易就把别的进程的数据篡改了嘛。
2、每个进程在创建之初,它所需要的内存大小都是不确定的。如果按照您的说法直接给进程分配固定的物理内存,假如两个进程在创建之初都直接各自分配了 1G 的物理空间。但实际运行起来,A 进程只用了 100M,而 B 进程需要 1.9 G。那么给 A 进程分配的空间就浪费了,而给 B 进程分配的空间又不够。都采用虚拟地址,表面看上去每个进程都可以独占内存的所有空间。在进程运行的途中再对虚拟地址和物理地址进行转换,可以有效的利用空间。甚至在内存不足的情况下,还可以把进程的内存存到硬盘里,切换到该进程时再从硬盘读取。
3、虚拟内存可以为每个进程提供一个一致的地址空间,这样程序员就不需要管理内存了,这也降低了编程的复杂度。

进程通信为什么又要共享内存?
因为有时候两个进程需要进行大量的通信,并且传递的都是比较大的数据。那么采用管道或者消息队列的方式就不方便了。这不如两个进程都拿出一块虚拟地址,映射到相同的物理内存中。这样进程间需要传送的数据就不需要来回拷贝了,这边一写那边立马看到了。共享内存理论上是最快的进程通信方式,不过有个弊端就是不能跨物理机进程通信,如果需要跨物理机进行进程通信,建议用套接字。
在这里插入图片描述

我们需要通过一些手段保证在数据被写入之前不允许其他进程从共享内存中读取。比较常见的解决办是通过 信号量 来进行同步

用代码实现一下共享内存可以不?

(1)既然需要用共享内存,首先需要创建一个共享内存或者得到一个共享内存。这一步要用到一个函数就是 shmget。

int shmget(key_t key,size_t size, int flag);
//key:用来定位共享内存
//size:用来指定共享内存的大小
//flag:用来表示创建共享内存的方式,如果赋值是 IPC_CREAT 表示创建一个新的
//返回值:共享内存标识符

(2)通过第一步创建好了共享内存,但是如果一个进程想要访问这段共享内存,那么就需要将共享内存加载到自己的虚拟地址空间中。而加载的这个过程就需要用到下面这个函数。

void *shmat(int shmid, const void *shmaddr, int shmflag);
//shmid:传入共享内存标识符
//shmaddr:指定共享内存映射的地址
//shmflag:标识内存关联后的读写权限
//返回值:返回共享内存映射到进程空间的起始地址。

(3)经过前两步,所有与共享内存进行关联的进程,就可以进行通信了。这一步不需要什么特殊的函数,直接往共享内存中写入,或者从中读取就可以啦。

(4)如果内存共享使用完毕,那么就需要解除绑点,然后再删除共享内存对象。这需要用到下面两个函数。

int shmdt(void *addr);
//addr:共享内存的起始地址
void *shmctl(int shm_id, int cmd, struct shmid_ds *buf);
//shm_id:共享内存标识符
//cmd:对共享内存的操作,如果用IPC_RMID表示要将共享内存删去。
//buf:共享内存管理结构体。
//shared_memory.h
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>   //刚才介绍的几个函数都在这个库中
#include <unistd.h>
#define PATHNAME "/home/dabai/server.c" //路径名,用它来获取共享内存标识符的key
#define PROJ_ID 0x6666 //整数标识符
#define SIZE 4096 //共享内存的大小//server.c
#include "shared_memory.h"
int main()
{key_t key = ftok(PATHNAME, PROJ_ID); //建立共享内存需要一个区域标识符来标识共享内存区域,ftok把已经存在的路径名和整数标识符转换成一个整数 IPC 键值。//如果key创建失败则返回值小于0,应该有个打印错误并结束程序的操作,为了代码简洁我就不写啦。int shm = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666); //创建新的共享内存,返回共享内存标识符//如果共享内存创建失败则返回值小于0,应该有个打印错误并结束程序的操作,为了代码简洁我就不写啦。printf("key: %x\n", key);printf("shm: %d\n", shm);char* mem = shmat(shm, NULL, 0); //关联共享内存//这里还是应该检查下是否关联成功为了代码简洁我就省略了int i = 0;while (1){mem[i] = 'a';    //进程可以根据自己的需要在这里对共享内存进行写入或读出。i++;}shmdt(mem); //共享内存去关联shmctl(shm, IPC_RMID, NULL); //释放共享内存return 0;
}

这篇关于916-关于共享内存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/344665

相关文章

【Linux】Linux 共享内存:高效的进程间通信

文章目录 Linux 共享内存:高效的进程间通信1. 什么是共享内存?2. 共享内存的实现步骤2.1 创建共享内存2.2 映射共享内存2.3 读写共享内存2.4 解除映射和删除共享内存 3. 共享内存的同步问题信号量示例: 4. 共享内存的优势与劣势优势:劣势: 5. 使用场景6. 结论 Linux 共享内存:高效的进程间通信 共享内存(Shared Memory)是 Li

c++ linux——进程共享内存

共享内存概念: 每个进程的虚拟内存对应一块物理地址,如果两个进程需要共享某一块内存,则各自的虚拟内存会有一小块映射到同一片物理地址上。是最高效的进程间通信方式。 关键就是四个函数 shmget(创建或者获取现有的共享内存标识符) shmat (将共享内存挂接到当前进程) shmdt(共享内存与当前进程取消挂接) shctrl(删除共享内存或者改变权限) 举例实现: 进程1 #include<sy

进程间通信方式(共享内存、信号灯集、消息队列)

共享内存 特点 1)共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。 2)为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程 将其映射到自己的私有地址空间。进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。 3) 由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等 使

github源码指引:共享内存、数据结构与算法:树形结构ListTree

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。         专题:共享内存、数据结构与算法_初级代码游戏的博客-CSDN博客         本文讲解带有子项的链表。 一、介绍         与

C++共享内存交互方式

一、什么是共享内存 文件映射是一种实现进程间单向或双向通信的机制。它允许两个或多个本地进程间相互通信。为了共享文件或内存,所有的进程必须使用相同的文件映射的名字或是句柄。 说白了就是把内存当成磁盘,在内存上新建一个文件,其它进程只要知道这个文件的名字,就可以直接获取该内存文件上的数据。 二、实现步骤 为了实现共享文件,进程先调用OpenFileMapping方法,如果内存没有相应的文件可以使用::

共享内存的使用

一、共享内存的原理 共享内存是目前Linux进程间通信里面最高效、最简单的一种方式。它允许多个进程同时访问同一个内存,并不需要通过系统调用或者内核切换来完成,所以它的效率是所有IPC通信中最高的。在Linux开发中,共享内存常用于一个进程向另一个进程进行图像传输、结构体传输等。 共享内存的原理是它是从内核空间中申请一块内存区域,然后把这个区域的数据映射到不同的进程里面。然后多个进程

【Linux修行路】进程通信——共享内存

目录 ⛳️推荐 一、直接原理 1.1 共享内存的的申请 1.2 共享内存的释放 二、代码演示 2.1 shmget 2.1.1 详谈key——ftok 2.2 创建共享内存样例代码 2.3 获取共享内存——进一步封装 2.4 共享内存挂接——shmat 2.5 共享内存去关联——shmdt 2.6 释放共享内存——shmctl 2.7 开始通信 2.7.1 proc

IO进程day06(进程间通信、信号、共享内存)

目录 【1】进程间通信 IPC 1》 进程间通信方式 2》 无名管道 1> 特点 2> 函数接口 3> 注意事项 练习:父子进程实现通信,父进程循环从终端输入数据,子进程循环打印数据,当输入quit结束。 3》有名管道  1> 特点 2> 函数接口 3> 注意事项  练习:通过两个进程实现 cp功能  4> 有名管道和无名管道的区别 【2】信号  1》概念  2》信

windows下利用文件映射实现共享内存

windows下利用文件映射实现共享内存的办法比较简单,下面是实现代码,细节用注释说明. 调用类似linux下shm的操作.该类没有进行太多的测试,欢迎提出问题和bug~~:) #include <windows.h>#include <string>#include <iostream>#include <assert.h>using std::string;using std

Codeforces Round 916 (Div. 3) E1. Game with Marbles(博弈论*1400)

感觉很难想。 如果你直接想的话,你就会发现有很多做法可以选择,而你根本不知道应该选哪个。 这时候可以先假设鲍勃已经取走了爱丽丝的所有的颜色的弹珠,(并且以每个颜色一个弹珠的代价)。 这时候每一项得分就是 S i = − ( b i − 1 ) S_i = -(b_i - 1) Si​=−(bi​−1)。 然后我们使得这时候爱丽丝的操作为取回弹珠,即她可以选择一种颜色的弹珠,并且直接取回,鲍勃