目录

一、共享内存

1.1 申请共享内存块

1.2 释放共享内存块

1.3 挂接共享内存

二、共享内存的使用

2.1 Server端与Client端

2.2 挂接与运行

三、共享内存总结

3.1 共享内存的特点

3.2 共享内存实现访问控制


一、共享内存

共享内存是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,即进程不再通过执行进入内核的系统调用来传递彼此的数据,减少了拷贝的次数。

共享内存是操作系统提供的。

共享内存=共享内存块+对应的共享内存的内核数据结构。

接下来我们来看看其系统调用接口——shmget。

其作用是返回一个申请的System V的共享内存块。

1.1 申请共享内存块

返回值:

  • 成功则返回有效共享内存的用户层标识符(类似于文件的fd),失败则返回-1并设置错误码。

参数:

1.key:

  • server端根据key值创建共享内存,client端可以通过该唯一的key值找到对应的共享内存块。

2. size:

  • 想创建多大的共享内存

3.shmflg:

  • 有两个参数(IPC_CREAT、IPC_EXCL)
  • IPC_CREAT 表示创建共享内存,如果该共享内存已经存在,则获取该共享内存;如果该共享内存不存在,则创建共享内存并返回。
  • IPC_EXCL单独使用是无意义的,当配合IPC_CREAT使用时,如果该共享内存存在,则出错返回;如果不存在,则创建并返回。所以IPC_CREAT和IPC_EXCL一起使用一定能创建出一个共享内存。
  • 并可以传入内存的访问权限。

关于形成唯一的key值,我们还可以使用一个系统接口——ftok。

该接口的功能是将 pathname 和 proj_id 结合起来,通过算法计算出一个 key 值

返回值:

通过pathname和proj_id计算出一个System的 key 值。失败返回-1。

参数:

1.pathname:

传入一个路径,传入路径的的本质就是拿到该路径下的这个文件的inode值。

2.proj_id

项目id,可以传入0-255之间的整数即可,但是超过了,也会自动进行截断。

所以,接下来就是我们的第一步:创建公共的key值

接下来我们来使用一个ftok生成key值。

#define PATH_NAME "."   //.表示当前文件所在路径,该路径下一定要有权限
#define PROJ_ID 0x66
#define SHM_SIZE 4096    //共享内存的大小,最好是页(4096)大小的整数倍//Server端代码:
int main()
{key_t k = ftok(PATH_NAME, PROJ_ID);   //key_t 其实就是 int 类型Log("create key done", Debug) << "Server key:" << k << endl;return 0;
}//Client端代码:
int main()
{key_t k = ftok(PATH_NAME, PROJ_ID);Log("create key done", Debug) << "Client key:" << k << endl;return 0;
}

结果如下:两个文件生成的key值相同,这样我们就可以让两个进程访问一个共享内存。

有了key值的准备,接下来我们使用一下 shmget

    // 2.创建共享内存int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL);if (shmid == -1){perror("shmget error");exit(1);}

1.2 释放共享内存块

然后我们来观察结果,发现,在第一次创建时,共享内存确实开辟成功了,可是当我们再次运行时,因为上一次申请的共享内存没有释放,所以导致开辟空间出错。

所以,接下来我们学习一下查看ipc的命令,使用命令 ipcs-m 可以看到开辟出的共享内存块。

所以我们可以使用 ipcrm -m +shmid 来删除开辟的共享内存。因此我们可以知道,Ststem V IPC资源的生命周期是随内核的!

在程序中,我们便可以使用 shmctl 来释放共享内存

使用如下:

实现一个将十进制转化为十六进制的写法,可以让key值以十六进制进行显示。

1.3 挂接共享内存

接下来就是将我们的Client端挂接到Server端

shmat:

返回值:

返回共享内存的起始地址(类似于malloc),失败的话返回-1,并设置错误码。

参数:

1.shmid:

表示要挂接的共享内的标识符id。

2.shmaddr:

指定共享内存的起始地址,传入该参数可以对共享内存进行更多的操作;如果只是使用挂接,传入nullptr即可。

3.shmflg:

表示挂接方式,直接传入0,就表示以读写方式进行挂接。

shmdt:

返回值:

        成功返回0,失败返回-1,并设置错误码。

参数:

传入共享内存的起始地址即可释放。

首先我们将创建共享内存时的权限设置一下,这样进程才能挂接至共享内存中。

接下来是 shmat 与 shmdt 的使用,如下:

接下来我们编写一个脚本 while :;do ipcs -m; sleep 1;done 来实时监测共享内存的挂接情况(从0至1),这样程序就挂接上共享内存了。

二、共享内存的使用

2.1 Server端与Client端

我们接下来的目的是让Server端创建一块共享内存,然后Server端和Client同时挂接上共享内存,然后Client不断发送数据,Server端接收数据。

Server端代码(创建、释放、挂接、解挂接)

#define PATH_NAME "/home/wzh" /// 该路径下一定要有权限
#define PROJ_ID 0x66
#define SHM_SIZE 4096 // 共享内存的大小,最好是页(4096)大小的整数倍
#include "comm.hpp"string TransToHex(key_t k)
{char buffer[32];snprintf(buffer, sizeof(buffer), "0x%x", k);return buffer;
}int main()
{key_t k = ftok(PATH_NAME, PROJ_ID);Log("create key done", Debug) << "Server key:" << TransToHex(k) << endl;// 2.创建共享内存int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666);if (shmid == -1){perror("shmget error");exit(1);}// 3.将指定的共享内存,链接到自己的地址空间char *shmaddr = (char *)shmat(shmid, nullptr, 0);Log("attcah shm done ", Debug) << "shmid : " << shmid << endl;printf("shmaddr:%p\n", shmaddr);//进行通信://服务端进行读取sleep(3);for (;;){if (*(shmaddr + 55) == 'd')break;printf("%s\n", shmaddr);sleep(1);}// 4.将指定的共享内存,从自己的地址空间中去关联int n = shmdt(shmaddr);Log("detach shm done", Debug) << "shmid : " << shmid << endl;cout << "n:" << n << endl;// 删除共享内存shmctl(shmid, IPC_RMID, nullptr); // 选项IPC_RMID 功能是删除共享内存Log("rm shm done", Debug) << "shmid : " << shmid << endl;return 0;
}

然后我们编写Client端的代码

#include "comm.hpp"int main()
{// 1.创建公共的key值key_t k = ftok(PATH_NAME, PROJ_ID);Log("create key done", Debug) << "Client key:" << k << endl;//2.寻找共享内存(IPC_CREAT)int shmid = shmget(k, SHM_SIZE, IPC_CREAT);if (shmid < 0){Log("create shm done", Error) << "Client key:" << k << endl;exit(2);}//3.挂接char *shmaddr = (char *)shmat(shmid, nullptr, 0);printf("shmaddr:%p\n", shmaddr);// 4.使用// 将共享内存看作一个char形的bufferfor (char a = 'a'; a <= 'z';a++){// 每一次都向shmaddr[共享内存的起始地址进行写入]snprintf(shmaddr, SHM_SIZE - 1,"hello serve , 我是Client进程 我的pid:%d,inc:%c\n", getpid(), a);sleep(1);}// 5.去关联int n = shmdt(shmaddr);assert(n != -1);Log("detach shm success", Debug) << "Client key:" << k << endl;return 0;
}

2.2 挂接与运行

先运行Server端创建共享内存,然后让client去关联申请的共享内存,然后我们来观察现象:

现象如下:Server端和Client端成功挂接上共享内存:

接下来将代码运行起来,测试两个进程间能否通信成功:

三、共享内存总结

3.1 共享内存的特点

堆栈相对而生,其中这块区域就是可以存放共享内存、内存映射和共享库,如果双方进程想进行通信,可以直接进行访问,也就是内存级的读和写。

之前在文件操作中,我们使用系统调用read、write这些操作,这些属于内核级操作。而共享内存的使用是直接在进程内部进行操作的,所以效率比管道高,其不用经过内核处理。

共享内存被创建,默认申请为全零。

结论1:只要是通信双方使用shm,一方直接向共享内存中写入数据,另一方面就可以立马看到数据。

共享内存是所有进程间通信(IPC)中速度最快的,不需要过多的拷贝!

共享内存是速度最快的拷贝方式,因为直接访问内存本质是减少了拷贝的次数。

结论2:共享内存缺乏访问控制!会带来并发问题。比如写方还没有将数据写完,读端就将数据读取了。

鉴于共享内存无法实现访问控制,我们可以额外创建管道来实现共享内存的访问控制。

3.2 共享内存实现访问控制

首先我们使用 Init类,当创建对象时,就创建了fifo管道,当进程结束时fifo自动删除。

然后我们定义以下4个接口,OpenFIFO、Wait、Signal、Closefifo本质对应的是open打开fifo文件;Wait对应read等待数据的写入,无数据则阻塞;Signal对应Client端进行write写入数据;Closefifo调用close关闭文件。

class Init
{
public:Init(){umask(0);int n = mkfifo("./fifo", 0666);assert(n == 0);(void)n;Log("create fifo success", Notice) << endl;}~Init(){unlink("./fifo");Log("create fifo success", Notice) << endl;}
};
//创建管道
Init init;#define READ O_RDONLY
#define WRITE O_WRONLY
int OpenFIFO(string pathname, int flags)
{Log("等待中……", Notice) << endl;int fd = open(pathname.c_str(), flags);assert(fd >= 0);return fd;
}void Wait(int fd)
{uint32_t temp = 0;ssize_t s = read(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));Log("唤醒中……", Notice) << endl;
}
void Signal(int fd)
{uint32_t temp = 1;ssize_t s = write(fd, &temp, sizeof(uint32_t));assert(s == sizeof(uint32_t));(void)s;
}
void Closefifo(int fd)
{close(fd);
}
//Server端改动:int fd = OpenFIFO("./fifo", READ);for (;;){Wait(fd);printf("%s\n", shmaddr);sleep(1);if (strcmp(shmaddr, "quit") == 0){printf("quit\n");break;}}Closefifo(fd);//Client端改动:int fd = OpenFIFO("./fifo", WRITE);while (true){ssize_t s = read(0, shmaddr, SHM_SIZE - 1);Signal(fd);if (strcmp(shmaddr, "quit") == 0)break;}Closefifo(fd);

这样,server端就具有了访问控制,如果没有数据,则阻塞等待数据。

【Linux】共享内存相关推荐

  1. linux的共享内存,linux共享内存实际在哪里?

    我只想知道共享内存驻留在Linux系统中的位置?它在物理内存还是虚拟内存中?linux共享内存实际在哪里? 我知道有关进程的虚拟内存发送信箱,他们从不同的工艺处理和流程没有看到对方的记忆,但我们可以利 ...

  2. Linux共享内存(二)

    Linux共享内存编程实例 原文链接:http://blog.csdn.net/pcliuguangtao/article/details/6526119 /*共享内存允许两个或多个进程进程共享同一块 ...

  3. c++ 共享内存_关于Linux共享内存的实验 [二] - 原因

    关于Linux共享内存的实验 [一] 上文采用的"删文件"和"杀进程"的方法主要是为了快速演示实验现象,但这种做法不利于通过调试手段进一步探究其内在的逻辑.为此 ...

  4. 【Linux共享内存】

    Linux共享内存 一.基本概念 二.常用函数 1. shm_open 2. mmap 3. munmap 4. shm_unlink 5. ftruncate 三.使用示例 四.share内存不足解 ...

  5. linux 共享内存操作(shm_open、mmap、编译链接库:-lz -lrt -lm -lc都是什么库)

    文章目录 linux 共享内存操作(shm_open) 一.背景 二.函数使用说明 shm_open ftruncate(改变文件大小) mmap共享内存 三.示例代码 创建内存共享文件并写入数据 打 ...

  6. linux 共享内存 查看和删除

    在使用共享内存的程序异常退出时,由于没有释放掉共享内存,在调试时会出现错误.您可以使用shell命令来查看与释放已经分配的共享内存,下面将详细说明如何进行查看和释放分配的共享内存的方法. 预备知识 L ...

  7. Linux共享内存编程实例

    /*共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间)从而使得这些进程可以相互通信.在GNU/Linux中所有的进程都有唯一的虚拟地址空间,而共享内存应用编程接 ...

  8. LINUX共享内存使用常见陷阱与分析(转)

    所谓共享内存就是使得多个进程可以访问同一块内存空间,是最快的可用IPC形式.是针对其他通信机制运行效率较低而设计的.往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥.其他进程能把同一段共 ...

  9. linux 共享内存_盘点那些linux 后台开发类常见问题及知识点

    一.linux和os: netstat :显示网络状态 tcpdump:主要是截获通过本机网络接口的数据,用以分析.能够截获当前所有通过本机网卡的数据包.它拥有灵活的过滤机制,可以确保得到想要的数据. ...

  10. linux 共享内存_什么是物理/虚拟/共享内存——Linux内存管理小结一

    物理内存和虚拟内存到底有什么区别? 提到内存,我们会想到经常接触的三个词:虚拟内存.物理内存.共享内存.它们分别对应top输出中的VIRT.RES.SHR三列. 1. 物理内存 系统的物理内存被划分为 ...

最新文章

  1. 用Elevator优化AV1视频播放
  2. sqlldr 导入乱码,Oracle客户端字符集问题
  3. ASP.NET Core Web API基于RESTFul APIs的集合结果过滤和分页
  4. Django04-2: ORM关系表\字段补充
  5. #define typedef 区别
  6. c语言编辑的库存管理软件,C语言课程设计,商品库存管理系统怎么做啊?
  7. NAT原理?代理服务器原理?
  8. 录像的视频如何在画面中实时加上时间戳
  9. 关于求已知整数数组的连续子数组的最大和的方法 ——基于软件工程的要求给予优化...
  10. 在html页面中封装elementUi的tree树结构
  11. 《深入浅出通信原理》学习(1-8)
  12. word论文公式编号排版
  13. JavaSE Map集合 HashMap和Hashtable的区别 Collections(集合工具类) 集合练习 模拟斗地主(洗牌,发牌,看牌)
  14. cs1.5小地图如何加机器人 电脑人 POD2.5
  15. Duilib嵌入cef3,实现浏览器功能
  16. 淘宝商品信息爬取(已登录)
  17. 近义句子转换软件 - 同义词转换器软件
  18. oracle 根据sid psid,如何获得所有windows用户的SID
  19. 纯 CSS3 实现漂亮的 input 输入框
  20. 为什么应该为“数据时代原住民”打造智能产品?

热门文章

  1. Icon图标制作(转化)工具
  2. pycharm 配置 interpreter
  3. Fortran库函数atan与atan2
  4. 云技术背景下ssl证书可以提供怎样的安全服务呢?
  5. ASO和ASM的关系与区别
  6. mac 微信备份到外接硬盘方案(软链接)
  7. Sobel算子->方向滤波
  8. ORACLE函数库大全
  9. 空闲时间不要接私活,要提升自己
  10. tensorflow自定义GPU版本op节点