【Linux】-进程间通信-共享内存(SystemV),详解接口函数以及原理(使用管道处理同步互斥机制)

在这里插入图片描述

💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、共享内存的原理
  • 二、直接代码
    • 2.1关于共享内存的四大接口
    • 2.2如何通信
  • 三、扩展知识
    • 3.1 看看维护共享内存的结构体属性
    • 3.2 使用管道来实现同步互斥机制
  • 四、总结


前言

今天我们来讲进程间通信的的另一个通信方式,在第一篇讲解进程间通信的博客中,博主就提到了SystemV标准的通信方式,我们前面讲解的匿名管道和命名管道都是基于文件的,但是共享内存不是基于文件的,他的所有进程间通信最快的,因为他的拷贝少,共享内存的难点就在于他的接口多,复杂,因为SystemV标准下不止一个共享内存,还有消息队列和信号量,都需要类似的接口,为了可以更好的复用接口函数,接下来博主就来带大家学习共享内存。


讲解逻辑:

  1. 直接原理,讲解周边问题
  2. 通过原理,写一部分代码,认识系统接口,进行测试
  3. 扩展代码去讲解

一、共享内存的原理

使用共享内存的目的是让进程间进行通信,但是进程间通信的本质是让不同的进程看到同一份资源,由共享内存这个名字可知,这篇共享的资源是一块内存,计算机中我们一般由的地址要不是虚拟地址,要不是物理地址,想形成可执行程序里面的地址我们目前不谈,而虚拟地址是每个进程特有的,所以我们猜测这块共享内存是物理内存的一块,因为有了前面的两次通信方式的铺垫,我们已经慢慢找到规律了,那博主就以一份图给大家讲解一下共享内存的原理。
在这里插入图片描述

共享内存的原理很简单,就上幅这个图片,但是博主要讲一些周边问题:

  1. 释放共享内存,先去挂接,再释放内存,是相反的操作
  2. 上面的操作都是进程直接做的吗??不是,是直接由os去做的,原因涉及到物理内存了。
  3. 那既然有os去操作的,那么我们去创建,使用或者释放都需要经过系统调用接口去让os帮助我们实现
  4. 我们的不同进程通过共享内存进行通信,另外的进程也需要通过共享内存来进行通信,那么共享内存就不止一块,由许多快,那么这块共享内存都是需要管理起来的,所以先描述再组织,就对应我们上图的struct结构体。里面存放的是对共享内存的管理属性。

所以我们一会对共享内存的使用里面肯定会涉及到这个结构体里面的属性,等会遇到了一个讲一个,现在都讲解出来读者大概率不会理解。

二、直接代码

我们通过刚才的原理分析,而且这些操作是需要通过系统调用接口的,所以我们一步步的来介绍这些系统调用接口。

2.1关于共享内存的四大接口

一、申请共享内存接口
在这里插入图片描述

  1. 返回值(用户层)shmid:此函数申请一块共享内存,返回共享内存标识符,可以先理解为和文件描述符唯一标志文件一样的道理。
  2. 第二个参数,是申请共享内存的大小。单位是字节
  3. 第三个参数:共享内存是为了给不同的进程使用,那么使用这块内存之前,只要由一个进程创建,其他进程拿来用就行了,那这个参数就是控制对共享内存的权限操作,来看我们自己要掌握的权限在这里插入图片描述
    (1)IPC_CREAT:(单独使用)如果你申请的共享内存不存在就创建,存在就获取返回
    (2)IPC_CREAT | IPC_EXCL:如果你申请的共享内存不存在就创建,存在就报错,这是保证了你创建的共享内存是最新的。IPC_EXCL不单独使用
    (3)第三个就是传我们对应的权限,如0666

上面的方式我们再讲解文件操作的时候就讲解过了,write函数里面需要传这样的参数,这些大写字母起始就是对应的宏。

  1. 第一个参数:通过第三个参数,我们怎么知道这个共享内存存不存在,就好比你怎么保证让不同的进程看到同一份共享内存是一样的,此时就有了我们的第一个参数,接下来谈谈这个key。
    (1)key是一个数字,这个数字是多少不重要。关键在于他必须再内核中具有唯一性,能够让不同的进程进程唯一标识
    (2)第一个进程可以通过key来创建共享内存。第二个进程之后的进程,只要拿着这个key就可以和第一个进程看到同一个共享内存了
    (3)对于一个已经创好的共享内存,key在哪??大家还记得一个说管理共享内存的结构体吗,key就在共享内存的描述对象里
    (4)通过第一点想要key去唯一标识共享内存,大家再回想一下命名管道是怎么唯一标识的,是不是通过就和文件名,所以这个key应该也类似于命名管道的标识方式。
    (5)通过第二点,我们通过key创建共享内存,那么第一次创建的时候,这个key怎么有???

我们总结出四个结论和一个问题,问题来到了这个key一开始时怎么产生的了,按照第四点的结论,我们来介绍一下这个函数ftok
在这里插入图片描述
第一个参数:路径这个随便写
第二个参数,这个是工程id,我们可以随便去指定是一个数字
返回值(内核层):是一个共享内存标识符

我们上面的两个参数都是由用户自己去定义的,所以可能会和系统中的key产生冲突,这个函数是通过一个算法将两个参数进行运算的出来的这样的一个key,每次生成的结果都是不一样的,不是你每次传的参数一样计算出来的结果就是一样的。这样为什么就可以做到key是唯一的呢,我们的路径是唯一的,而且第二个参数是我们自己传,大概率也是唯一的,这样就导致我们的key是唯一的,而且一旦创建这个key就是这个共享内存所独有了,如果再生成这个key,只能获取,不会再创建一个新的了
为什么key不由os自己创建呢,我们自己创建还有可能造成key冲突的问题??
(1)再谈谈key的时候的第二点我们知道这个我们通过创建共享内存是由一个进程去创建另一个进程去使用就可以,如果这个key是os生成的,创建好的共享内存,那另一个没有关系的进程怎么获取这块共享内存,因为共享内存不是唯一的,所以os里面的key也不是唯一的,所以没有办法给另一个进程让他获取啊,有的人说传给另一个进程,这样就出现蛋生鸡的问题,另一个进程要key才能进行通信,但是要key必须先通信,如果共享内存的个数是唯一的,那么可以让os自己生成,大家自己理解一下
(2)这个key的获取可以说是用户的约定,和哪个进程通信只有用户知道,就是程序员知道,两个进程使用ftok这个相同的方式就可以获取唯一的key,因为这两个参数是唯一的
(3)有的人会说我们将系统自己生成的key通过管道传给另一个进程就可以了,答案确实可以,但是这样我们学习共享内存的成本就搞了,还要先学习管道,这样也不嫩恶搞保证共享内存是一个独立通信模块了

大家看到这里对于key的理解应该到位了,但是有一个关键的点,key vs shmid

这两个都是共享内存的标识符,他两有一个不就行了,key是内核中唯一标识的,shmid只有再进程里唯一标识的,我们操作共享共享内存的函数都是使用shmid。

通过上面的一系列分析,我们来申请一块共享内存:shmget+ftok
sham.hpp:

#ifndef __COMM_HPP__
#define __COMM_HPP__

#include <iostream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "log.hpp"

using namespace std;

Log log;

const int size = 4096; 
const string pathname="/home/xdh";
const int proj_id = 0x6666;


key_t GetKey()
{
    key_t k = ftok(pathname.c_str(), proj_id);
    if(k < 0)
    {
        log(Fatal, "ftok error: %s", strerror(errno));
        exit(1);
    }
    log(Info, "ftok success, key is : 0x%x", k);
    return k;
}

int GetShareMemHelper(int flag)
{
    key_t k = GetKey();
    int shmid = shmget(k, size, flag);
    if(shmid < 0)
    {
        log(Fatal, "create share memory error: %s", strerror(errno));
        exit(2);
    }
    log(Info, "create share memory success, shmid: %d", shmid);

    return shmid;
}

int CreateShm()//创建共享内存得到标识符shmid,进行了封装
{
    return GetShareMemHelper(IPC_CREAT | IPC_EXCL | 0666);
}
#endif

processa.cc:

#include"sham.hpp"
//这是进程a,有这个进程创建共享内存
int main()
{
    //申请共享内存
    int shmid=CreateShm();
    sleep(5);
    return 0;
}

在这里插入图片描述

通过结果我们发现,我们第一次运行程序的时候申请了一块共享内存获得了共享内存标识符,但是第二次运行的时候显示就存在了,我们使用ipcs -m 查看共享内存,我们得出结论,进程结束了,我们的共享内存还是存在的,共享内存的生命周期是随着内核的,不是随着进程的,通过原理图也不难理解这点,没有关闭共享内存,这也可能会造成内存泄漏,类似于malloc。

这里面我们再来研究一个点,我们申请4097个字节大小的空间看看效果
在这里插入图片描述
我们看到大小是4097,在内核里面,我们的os实际上会给我们的4096*2大小的空间,但是我们只能使用4097,这个大家要记住,所以建议还是申请4096点整数倍,折合人民币我们内存的页宽有关系,大家先不用了解。

二、.挂接共享内存:shmat函数
我们的共享内存申请好了,我们就需要将其挂接到我们的地址空间上,就是原理图上的第二步
在这里插入图片描述

  1. 第一个参数:就是传刚才使用shmget函数的返回值即可是共享内存的唯一标识符
  2. 第二个参数:指定挂接到那个位置,我们申请好了共享内存,要挂接到我们进程的地址空间的共享群位置,这么多位置总要找到一个位置的其实位置吧,这样也方便我们页表进行映射,所以需要制定,我们在这里传空指针就好了,意思让系统自己决定
  3. 第三个参数:是挂接的方式

在这里插入图片描述
我们在这里传0进去就好了

  1. 返回值:我们就是把挂接到地址空间的那块位置的首地址返回出来,让用户能拿到,进行操作,所以返回值是void需要强转,和malloc类似,失败就返回(void)-1

我们来看代码实现:

//将共享内存挂接到自己的地址空间
    char* shmaddr=(char*)shmat(shmid,nullptr,0);
    if(*shmaddr<0)
    {
        log(Fatal,"shmat flase:%s",strerror(errno));
        exit(3);
    }
    log(Info,"shmat sucessful:%s",strerror(errno));
    sleep(3);

在这里插入图片描述

我们来观察一下nattch这个属性,他就是表示这块共享内存当前的挂接树,没调用这个shmat函数之前为0,调用之后为1,而且当进程退出他的挂接数自然的就减少了1

三.去掉挂接关系:shmdt
刚才是因为程序结束,挂接数减少了,但我们有时候程序没结束就像去挂接,怎么做??我们通过shmdt来去挂接,来看文档
在这里插入图片描述

这个函数非常的简单,就是传刚才挂接函数返回值就可以了,我们直接来看使用效果:
我们分析,我们3秒后创建共享内存,5秒后挂接进程,挂接数变成1,3秒后,去挂接,挂接数变成1,在3秒后程序终止,

int n=shmdt(shmaddr);
    if(n<0)
    {
        log(Fatal,"shmdt flase:%s",strerror(errno));
    }
    log(Info,"shmdt sucessful:%s",strerror(errno));
    sleep(3);

在这里插入图片描述

和我们预测的一样,我们的挂接数不一定非得在程序结束才会减1

四.释放共享内存:shmctl
我们想要将我们的共享概念内存释放掉使用shmctl
在这里插入图片描述

第一个参数:共享内存唯一标识符
第三个参数:是一个描述共享内存的状态和访问权限的数据结构,也就是我们开头说的描述共享内存的结构图,看到key在里面了吧,对于这个参数我们可以传一个null,因为不需要将状态获取到,这是一个输出型参数和status一样。
第二个参数:将要采取的动作,就是对第三个参数实行什么样的操作,有三个操作

在这里插入图片描述
我们关注的是最后一个,删除共享内存

来看操作:

 int n1=shmctl(shmid,IPC_RMID,nullptr);
    if(n1<0)
    {
        log(Fatal,"shmctl flase:%s",strerror(errno));
    }
    log(Info,"shmctl sucessful:%s",strerror(errno));
    sleep(3);

在这里插入图片描述

通过结果验证我们的讲解,我们也可以通过ipcrm -m +shmid来删除共享内存,这个大家下去试试,但是shmctl传进去的操作不一样,功能就不一样,如果传IPC_STAT,就可以查看属性。


我们将另一个进程也挂接到这个共享内存上吧,因为申请和释放进程a帮助我们做了,我们做的就是挂接和去挂接就可以了,来看进程b的代码:
先展示进程a的代码:

#include"sham.hpp"
//这是进程a,有这个进程创建共享内存
int main()
{
    sleep(3);
    //申请共享内存
    int shmid=CreateShm();
    
    sleep(5);

    //将共享内存挂接到自己的地址空间
    char* shmaddr=(char*)shmat(shmid,nullptr,0);
    if(*shmaddr<0)
    {
        log(Fatal,"shmat flase:%s",strerror(errno));
        exit(3);
    }
    log(Info,"shmat sucessful:%s",strerror(errno));
    sleep(3);


    //去挂接
    int n=shmdt(shmaddr);
    if(n<0)
    {
        log(Fatal,"shmdt flase:%s",strerror(errno));
    }
    log(Info,"shmdt sucessful:%s",strerror(errno));
    sleep(3);

    //释放共享内存
    int n1=shmctl(shmid,IPC_RMID,nullptr);
    if(n1<0)
    {
        log(Fatal,"shmctl flase:%s",strerror(errno));
    }
    log(Info,"shmctl sucessful:%s",strerror(errno));
    sleep(3);
    return 0;
}

进程b:

#include "sham.hpp"

int main()
{

    sleep(3);
    int shmid=GetShm();//这个函数在sham.hpp里面写就行了,获取shmid
    sleep(5);
     //将共享内存挂接到自己的地址空间
    char* shmaddr=(char*)shmat(shmid,nullptr,0);
    if(*shmaddr<0)
    {
        log(Fatal,"shmat flase:%s",strerror(errno));
        exit(3);
    }
    log(Info,"shmat sucessful:%s",strerror(errno));
    sleep(3);



    //去挂接
    int n=shmdt(shmaddr);
    if(n<0)
    {
        log(Fatal,"shmdt flase:%s",strerror(errno));
    }
    log(Info,"shmdt sucessful:%s",strerror(errno));
    sleep(3);
    return 0;
}

在这里插入图片描述

我们也成功看到了挂接数变成了2,上面讲解的一切都是让两个不同的进程之间看到同一份资源,还没有开始通信

2.2如何通信

我们通过上面一系列的操作终于实现我们再原理图讲的内容了,该说不说,确实太复杂的,但是这一系列的操作,让他的通信显得非常的简单,我们共享内存就是一块物理内存,映射到我们进程的地址空间上,我们程序通过这块地址空间上的地址就可以直接访问这块物理空间,此时他就很想malloc申请空间,然后去使用这块空间的方法很想,我们一起来看操作,让b写,a读

a:

while(true)
    {
        cout<<"a say@"<<shmaddr<<endl;
        sleep(1);
    }

b:

while(true)
    {
        cout<<"b enter@";
        fgets(shmaddr,4096,stdin);
        sleep(1);
    }

在这里插入图片描述

结论:

  1. 我们我们两个进程对这块空间的操作是你搞你的我搞我的,两者不受任何影响,所以说明共享内存间是没有同步互斥机制的
  2. 我们的共享内存是所有进程中通信速度最快,因为拷贝少
  3. 我们的共享内存的数据是用户自己去维护的,所以这些看到和管道有不同的地方,没有清空数据,这是需要用户自己去决定的。

但是我们确实实现了两个进程间通信了,有问题我们一会来解决。

三、扩展知识

3.1 看看维护共享内存的结构体属性

我们刚才的参数都是为了描述共享内存的,所以维护共享概念给内存的属性有哪些呢,刚才其实也大致看到了一些。
在这里插入图片描述
我们通过代码看看我们刚才提到一下属性:

再a进程把通信代码改成下面的

 int count=0;
 struct shmid_ds shmds;
 while(true)
   {
       sleep(1);
       if(count==0)
       {
           shmctl(shmid, IPC_STAT, &shmds);
           cout << "shm size: " << shmds.shm_segsz << endl;
           cout << "shm nattch: " << shmds.shm_nattch << endl;
           printf("shm key: 0x%x\n",  shmds.shm_perm.__key);
           cout << "shm mode: " << shmds.shm_perm.mode << endl;
       }
       count++;
      
   }

在这里插入图片描述

3.2 使用管道来实现同步互斥机制

我们因为目前只学了System V的共享内存,我们想要解决这个问题,还可以使用信号量,但是这个我们不做重点介绍,等有机会我们在给大家讲解信号量是怎么解决共享内存的这个缺点,我们今天,就使用管道去解决这个问题吧,因为是不相关的进程,所以使用命名管道。


在这里插入图片描述

在这里插入图片描述

这个使用管道的方法其实和共享内存是一点关系没有,之根据他会阻塞就不会执行下面的代码,这样间接控制了。我们后面会简单介绍一下信号量是怎么解决这个问题的,但是知识带大家了解一下。

四、总结

今天我们学习了共享内存,学习成本和前面两个差不多,前面是原理的铺垫大家不容易理解,但是使用简单,二共享内存有了前面的原理铺垫,理解起来不难,但是后面的使用接口对大家来说可能是一个难度,大家下去好好把四大接口函数理解一下,这对博主下一篇讲解消息队列以及信号量有很大帮助,希望大家下来可以去自己实现博主这篇博客上面的内容,我们下篇再见

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/178049.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pyqt5的组合式部件制作(四)

对组合式部件的制作又改进了一版&#xff0c;组合式部件的子部件不再需要单独“提升为”&#xff0c;如果在模板文件的提升部件窗口内选择了“全局包含”&#xff0c;那么只需要在模板文件和应用文件中直接复制粘贴即可&#xff0c;部件的应用更为简便。如下图&#xff1a;按住…

docker、elasticsearch8、springboot3集成备忘

目录 一、背景 二、安装docker 三、下载安装elasticsearch 四、下载安装elasticsearch-head 五、springboot集成elasticsearch 一、背景 前两年研究了一段时间elasticsearch&#xff0c;当时也是网上找了很多资料&#xff0c;最后解决个各种问题可以在springboot上运行了…

>Web 3.0顶级干货教学:浅析区块链与货币关系

Web 3.0顶级干货教学&#x1f525;&#xff1a;浅析区块链与货币关系 尊重原创&#xff0c;编写不易 &#xff0c;帮忙点赞关注一下~转载小伙伴请注明出处&#xff01;谢谢 1.0 数字交易 最早一笔数字化交易 是在www.PizzaHut.com 在 1994 年产生的&#xff0c;但是有趣的事情…

oracle面试相关的,Oracle基本操作的SQL命令

文章目录 数据库-Oracle〇、Oracle用户管理一、Oracle数据库操作二、Oracle表操作1、创建表2、删除表3、重命名表4、增加字段5、修改字段6、重名字段7、删除字段8、添加主键9、删除主键10、创建索引11、删除索引12、创建视图13、删除视图 三、Oracle操作数据1、数据查询2、插入…

linux部署jar 常见问题

1.java -jar xxx.jar no main manifest attribute, in xxx.jar 一.no main manifest attribute, in xxx.jar 在pom.xml文件中加入&#xff1a; <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifac…

【DevOps】Git 图文详解(八):后悔药 - 撤销变更

Git 图文详解&#xff08;八&#xff09;&#xff1a;后悔药 - 撤销变更 1.后悔指令 &#x1f525;2.回退版本 reset3.撤销提交 revert4.checkout / reset / revert 总结 发现写错了要回退怎么办&#xff1f;看看下面几种后悔指令吧&#xff01; ❓ 还没提交的怎么撤销&#x…

QTableWidget——编辑单元格

文章目录 前言熟悉QTableWiget&#xff0c;通过实现单元格的合并、拆分、通过编辑界面实现表格内容及属性的配置、实现表格的粘贴复制功能熟悉QTableWiget的属性 一、[单元格的合并、拆分](https://blog.csdn.net/qq_15672897/article/details/134476530?spm1001.2014.3001.55…

Linux中的进程程序替换

Linux中的进程程序替换 1. 替换原理2. 替换函数3. 函数解释4. 命名理解程序替换的意义 1. 替换原理 替换原理 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的…

Vue 定义只读数据 readonly

readonly 让一个响应式数据变为 **深层次的只读数据**。 isReadonly 判断一个数据是不是只读数据。 应用场景&#xff1a;不希望数据被修改时使用。 readonly 深层次只读&#xff1a; <template><h1>reactive数据</h1><p>姓名&#xff1a;{{ info…

BUUCTF 梅花香之苦寒来 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 注意&#xff1a;得到的 flag 请包上 flag{} 提交 密文&#xff1a; 下载附件&#xff0c;解压得到一张.jpg图片。 解题思路&#xff1a; 1、用010 Editor看了一下&#xff0c;刚开始以为是修改宽高的题&#xff…

【C++干货铺】list的使用 | 模拟实现

个人主页点击直达&#xff1a;小白不是程序媛 C专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 list的介绍及使用 list的介绍 list的使用 list的构造 list迭代器的使用 list的增删查改 list的模拟实现 结点的封装 迭代器的封装 list成员变量 构造函数 …

22LLMSecEval数据集及其在评估大模型代码安全中的应用:GPT3和Codex根据LLMSecEval的提示生成代码和代码补全,CodeQL进行安全评估

LLMSecEval: A Dataset of Natural Language Prompts for Security Evaluations 写在最前面主要工作 课堂讨论大模型和密码方向&#xff08;没做&#xff0c;只是一个idea&#xff09; 相关研究提示集目标NL提示的建立NL提示的建立流程 数据集数据集分析 存在的问题 写在最前面…

一篇五分生信临床模型预测文章代码复现——Figure 10.机制及肿瘤免疫浸润(六)

之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…

【开源】基于Vue和SpringBoot的高校宿舍调配管理系统

项目编号&#xff1a; S 051 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S051&#xff0c;文末获取源码。} 项目编号&#xff1a;S051&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能需求2.1 学生端2.2 宿管2.3 老师端 三、系统…

C语言每日一题(35)有效的括号

力扣网 20 有效的括号 题目描述 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右…

黑马React18: Redux

黑马React: Redux Date: November 19, 2023 Sum: Redux基础、Redux工具、调试、美团案例 Redux介绍 Redux 是React最常用的集中状态管理工具&#xff0c;类似于Vue中的Pinia&#xff08;Vuex&#xff09;&#xff0c;可以独立于框架运行 作用&#xff1a;通过集中管理的方式管…

Vue生成二维码并进行二维码图片下载

1、安包 npm install vue-qr --save2、引入 // vue2.0 import VueQr from vue-qr // vue3.0 import VueQr from vue-qr/src/packages/vue-qr.vue new Vue({components: {VueQr} })<!-- 设备二维码 对话框 270px--><el-dialog title"点位二维码" :visible.…

【Java 进阶篇】Redis:打开缓存之门

介绍 Redis&#xff08;Remote Dictionary Server&#xff09;是一个高性能的键值对存储系统&#xff0c;被广泛用作缓存、消息中间件和数据库。它以其快速的读写能力、支持多种数据结构和丰富的功能而闻名。在这篇博客中&#xff0c;我们将深入了解Redis的概念、安装以及基本…

阿里云 ACK 新升级,打造智算时代的现代化应用平台

云布道师 今天&#xff0c;能想到的或是想不到的领域&#xff0c;对容器和 Kubernetes 的需求都居高不减&#xff0c;使这项技术正在真正走向无处不在。 在 2023 云栖大会上&#xff0c;阿里云云原生产品线容器服务负责人易立关于容器服务 ACK 在本届亚运会上应用的介绍&#…