当前位置: 首页 > news >正文

【linux】进程间通信——system V

system V

  • 一、system V介绍
  • 二 、共享内存
    • 2.1 共享内存的原理
    • 2.2 共享内存接口
      • 2.2.1 创建共享内存shmget
      • 2.2.2 查看IPC资源
      • 2.2.3 共享内存的控制shmctl
      • 2.2.4 共享内存的关联shmat
      • 2.2.5 共享内存的去关联shmdt
    • 2.3 进程间通信
    • 2.4 共享内存的特性
    • 2.5 共享内存的大小
  • 三、消息队列
    • 3.1 消息队列的概念
    • 3.2 消息队列接口
      • 3.2.1 消息队列的获取msgget
      • 3.2.2 消息队列的控制msgctl
      • 3.2.3 消息队列发送数据msgsnd
      • 3.2.4 消息队列获取msgrcv
  • 四、信号量
    • 4.1 信号量概念
    • 4.2 信号量的用处
    • 4.3 信号量的pv操作
    • 4.4 信号量接口
      • 4.4.1 信号量申请semget
      • 4.4.2 信号量控制semctl
      • 4.4.3 信号量操作semop
  • 五、总结

一、system V介绍

进程间通信除了通过管道,都是基于文件的通信方式,还有一种方式是:SystemV标准的进程间通信方式。SystemV是一个在OS层面专门为进程通信设计的一个方案。这些都是由计算机科学家和程序员设计的,并且需要给用户使用。

如果要给用户用,是以什么方式给用户使用的呢?在操作系统层面上,SystemV是OS内核的一部分,是为OS中多进程提供的一种通信方案。但是OS不相信任何用户,给用户提供功能的时候,采用系统调用。所以System V进程间通信,一定会存在专门用来通信的接口:system call。

因为在早期由很多的方案,但是我们需要统一使用一个方案,所以现在诞生了在统一主机内的进程间通信方案:system V方案

system V IPC提供的通信方式有三种: 共享内存、消息队列、信号量

二 、共享内存

2.1 共享内存的原理

前面说过两个进程要通信就需要看到同一块资源

而我们知道进程之间具有独立性,物理内存当中代码和数据也互相独立。
那么现在我们可以在物理内存中创建一个内存块,让不同的进程都能看到这个内存块,具体的做法如下:

1️⃣ 通过某种调用,在内存中创建一份内存空间。
2️⃣ 通过某种调用,让进程”挂接“到这份内存空间上。(将创建好的内存映射进进程地址空间)
在后面可能不会共享内存了。所以在不用共享内存的时候
3️⃣ 去关联(去挂接)。
4️⃣ 释放共享内存。

对于共享内存的理解:
OS内可能存在多个进程同时使用不同的共享内存来进行进程间通信,既然有多份共享内存,那么操作系统就要管理它们,按照前面学习的经验,先描述后组织,描述就是对共享内存的一系列属性进行描述,而后用数据结构组织起来,这样对共享内存的管理变成了对数据结构的操作。

2.2 共享内存接口

2.2.1 创建共享内存shmget

shmget:用来创建共享内存

 #include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);RETURN VALUEOn success, a valid shared memory identifier is returned.  On errir, -1 is returned, and errno is set to indicate the error.

参数说明:

size:共享内存的大小。
shmflag:通常有两种选项:IPC_CREAT、IPC_EXCL。
IPC_CREAT: 共享内存如果不存在,则创建,不存在则获取。
IPC_EXCL: 无法单独使用
IPC_CREAT | IPC_EXCL: 如果不存在就创建,如果存在就出错返回(保证共享内存是新创建的)。
如果shmflag是0默认就是IPC_CREAT。
key:保证看到同一份共享内存,能进行唯一性标识(就像省份证号码一样,数字不重要,只用来标识唯一性)。通过ftok函数转化
如果创建成功返回共享内存的标识符,如果失败则返回-1。

ftok:用来形成key

#include <sys/types.h>
#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);
RETURN VALUE
On success, the generated key_t value is returned.  
On failure -1 is returned, with errno indicating the error as for the stat(2) system call.

ftok第一个参数是自定义路径名,第二个参数是自定义的项目ID。最后唯一的共享内存ID就是通过路径名+项目ID来标识。最后生成的返回值并不重要,只要它能生成一个值来唯一标识这块共享内存就可以。
只要参数不变,生成的返回值就不会变。 这样就可以让两个进程拥有同一个key,就可以用key找到同一份共享内存。

key_t GetKey()
{key_t n = ftok(PATHNAME, PROJ_ID);if(n == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return n;
}int Creatshm(key_t key)
{int shmid = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666);if(shmid == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return shmid;
}int Getshm(key_t key)
{int shmid = shmget(key, SIZE, IPC_CREAT | 0666);if(shmid == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return shmid;
}

key的理解:
上面也说过了OS会把内存块管理起来,共享内存=物理内存块+共享内存的相关属性描述共享内存时就有一个字段struct shm中有key。 一个进程创建内存块后把key值写进相关属性中,而另一个进程拿着key值遍历相关属性查找。这样就完成了两个进程共享一块内存块。
我们发现key和shmid都是标识内存块的:key是在内核标识唯一性,而shmid是在用户层标识唯一性,这样即使操作系统有什么变化也不会影响用户使用,充分的解耦。他们的关系就类似于fd与inode。

2.2.2 查看IPC资源

共享内存的生命周期不是随着进程的,而是随着OS的,这也是所有system V进程间通信的特征。

ipcs -m 查看共享内存
在这里插入图片描述
ipcs -q 查看消息队列
ipcs -s 查看信号量
在这里插入图片描述

ipcs 三个一起查看
在这里插入图片描述
ipcrm -m shmid 删除共享内存
在这里插入图片描述

2.2.3 共享内存的控制shmctl

shmctl:控制共享内存

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

它的作用是对共享内存的控制
参数介绍:
shmid:控制共享内存的标识符。
cmd:控制的种类,主要用的是IPC_RMID(立即移除共享内存)。
buf:控制共享内存的数据结构,设置为空即可。
返回值:0表示返回成功,-1表示失败。

void Delshm(int shmid)
{if(shmctl(shmid, IPC_RMID, nullptr) == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}
}

2.2.4 共享内存的关联shmat

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

参数介绍:
shmaddr:可以指定虚拟内存,设置为nullptr即可。
shmflg:读取权限,默认为0。
返回值:返回共享内存的起始地址

void* Attachshm(int shmid)
{void* mem = shmat(shmid, nullptr, 0);if((long long)mem == -1L)// 64位指针8字节{std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return mem;
}

2.2.5 共享内存的去关联shmdt

去关联是指把进程和共享内存之间的映射关系删掉(修改页表),并不是删除共享内存。

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

它的参数就是在shmat返回的参数。
成功返回0,失败返回-1。

void Detachshm(void* start)
{if(shmdt(start) == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}
}

2.3 进程间通信

comm.hpp

#ifndef _COMM_HPP_
#define _COMM_HPP_#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>#define PATHNAME ".."
#define PROJ_ID 12345
#define SIZE 4096key_t GetKey()
{key_t n = ftok(PATHNAME, PROJ_ID);if(n == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return n;
}int Creatshm(key_t key)
{int shmid = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666);if(shmid == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return shmid;
}int Getshm(key_t key)
{int shmid = shmget(key, SIZE, IPC_CREAT | 0666);if(shmid == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return shmid;
}void Delshm(int shmid)
{if(shmctl(shmid, IPC_RMID, nullptr) == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}
}void* Attachshm(int shmid)
{void* mem = shmat(shmid, nullptr, 0);if((long long)mem == -1L)// 64位指针8字节{std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}return mem;
}void Detachshm(void* start)
{if(shmdt(start) == -1){std::cerr << errno << ":" << strerror(errno) << std::endl;assert(false);}
}#endif

shm_a.cc

#include "comm.hpp"int main()
{key_t k = GetKey();// 创建共享内存int shmid = Creatshm(k);// 挂接char* start = (char*)Attachshm(shmid);//使用while(true){if(strlen(start) > 4){printf("%s\n", start);}if(strlen(start) == 4){break;}sleep(1);}// 去关联Detachshm(start);// 删除共享内存Delshm(shmid);return 0;
}

shm_b.cc

#include "comm.hpp"int main()
{key_t k = GetKey();// 获取共享内存int shmid = Getshm(k);// 挂接char* start = (char*)Attachshm(shmid);// 使用std::string str = "hello shm";int cnt = 0;while(cnt != 8){snprintf(start, SIZE, "%s[%d]", str.c_str(),  cnt);cnt++;sleep(1);}std::string cmd = "stop";snprintf(start, SIZE, "%s", cmd.c_str());// 去关联Detachshm(start);return 0;
}

2.4 共享内存的特性

1️⃣ 共享内存是所有的进程间通信速度最快的。(优点)
2️⃣ 共享内存不提供任何同步或者互斥机制,不提供不代表不需要,所以需要程序员自行保证数据的安全!这也造成了共享内存在多进程中是不太安全的。(缺点)
3️⃣ 共享内存的生命周期是随OS的,而不是随进程的,这是所有System V进程间通信的共性。

为什么速度快呢?
管道和共享内存:考虑键盘输入,和显示器输出,对于同一份数据,共享内存有几次数据拷贝,管道有几次数据拷贝

管道:在这里插入图片描述
可以看到写到管道需要拷贝两次,而另一个进程读也需要两次,所以一共四次。如果考虑到输入输出外设,那么就是六次。

共享内存:
直接写入共享内存,直接从共享内存输出,所以是两次。考虑到输入输出的话就是四次。

2.5 共享内存的大小

这里讲的是shget的第二个参数,一般建议设置成4096(4KB)的整数倍,因为系统分享内存是以4KB为单位,假如我们申请的是4097,那么系统就会直接向上取整,也就是4096*2,但是我们只能使用其中的4097大小。

三、消息队列

3.1 消息队列的概念

消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法,读端和写端公用一个队列,每个数据块就是队列的一个节点,每个数据块都会有个记录类型的数据,来判断该数据块该被哪个进程读取。

3.2 消息队列接口

3.2.1 消息队列的获取msgget

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int msgget(key_t key, int msgflg);

这里的msgflg跟共享内存的两个参数一摸一样(IPC_CREAT、IPC_EXCL)。

返回值:msgget函数返回的一个有效的消息队列标识符

3.2.2 消息队列的控制msgctl

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>int msgctl(int msqid, int cmd, struct msqid_ds *buf);

参数说明:
msqid:消息队列的标识符。
其他的参数跟shmctl一样。

3.2.3 消息队列发送数据msgsnd

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

参数说明:
msqid:消息队列的用户级标识符
msgp:表示待发送的数据块(输出型参数)。
在这里插入图片描述

msgsz:表示所发送数据块的大小
msgflg:表示发送数据块的方式,一般默认为0即可
成功返回0,失败返回-1

3.2.4 消息队列获取msgrcv

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg)

参数跟上面msgsnd一致。

四、信号量

4.1 信号量概念

信号量本质上就是个计数器,它统计的是公共资源资源还剩多少

公共资源:可以被多个进程同时访问的资源,而如果访问没有被保护的公共资源,就会导致数据不一致问题(一个进程还在写的时候另一个进程就开始读)。所以公共资源需要保护,被保护起来的资源称为临界资源。而访问这些临界资源的那部分代码称为临界区。其他的代码就称为非临界区

保护公共资源:同步和互斥

互斥:当有多个进程想要访问同一份资源的时候,我们只允许一个进程访问,当这个进程访问完了,下一个进程才能访问。

原子性:要么不做,要么做完,只有这两种状态的情况。

既然我们想让多个进程看到同一个计数器,那么信号量也是个公共资源

4.2 信号量的用处

举个例子,假设我们要去看电影,而里面的座位只有我们买了票才能拥有,这里的票就是信号量,我们买了一张后,信号量就--

所以当我们想要某种资源的时候,我们可以进行预定(买票成功)。
共享资源可以作为一个整体使用或者划分成多个子资源部分。大部分都是整体使用,比如果管道。

如果我们申请成功,相当于我们预定了共享内存中的一小部分资源。如果不成功,就不能访问共享资源,以达到保护其他进程的目的。

在访问公共资源前要先申请信号量,而信号量本身就是个公共资源,那么信号量也带保护自己的安全。那么如何保证呢?

4.3 信号量的pv操作

信号量操作本质上就是计数器的++或者--,是原子性的。当我们预定资源的时候(--)称为p操作,释放资源(++)称为v操作。
如果信号量的初始值是1就代表了访问公共资源作为一个整体来使用,一个进程申请了别的进程就不能再申请了,我们把只有两种状态的信号量称为二元信号量

4.4 信号量接口

4.4.1 信号量申请semget

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>int semget(key_t key, int nsems, int semflg);

参数介绍:

nsems:表示申请信号量的个数
第一个和第三个参数就跟前面的shmget相同。
返回值:信号量集创建成功时,semget函数返回的一个有效的信号量集标识符

4.4.2 信号量控制semctl

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, ...);

参数介绍:
semid:信号量标识符
semnum:信号量的下标,默认0

4.4.3 信号量操作semop

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semop(int semid, struct sembuf *sops, unsigned nsops);

参数介绍:
sembuf:一个结构体

在这里插入图片描述
sem_num:信号量下标。
sem_op:1表示++p操作,-1表示--v操作。
sem_flg:选项设为0即可。

nsops:有多少个sembuf结构体。

五、总结

我们可以发现,共享内存、消息队列、信号量接口相似度非常高,尤其是获取与删除,这些都是system V标准的进程间通信
他们的第一个成员都是ipc_perm

struct ipc_perm {key_t          __key;    /* Key supplied to shmget(2) */uid_t          uid;      /* Effective UID of owner */gid_t          gid;      /* Effective GID of owner */uid_t          cuid;     /* Effective UID of creator */gid_t          cgid;     /* Effective GID of creator */unsigned short mode;     /* Permissions + SHM_DEST andSHM_LOCKED flags */unsigned short __seq;    /* Sequence number */};

我们可能会申请共享内存、消息队列、信号量的任意一种,那么操作系统如何组织它们呢?

因为ipc_perm是一样的,所以可以维护一个struct ipc_perm*的指针数组,存共享内存、消息队列、信号量它们的第一个元素的地址,也就是&ipc_perm
而我们知道结构体的第一个成员的地址和结构体对象的地址在数字上是相等的

所以当我们想使用的时候直接强转成想用的结构体(共享内存、消息队列、信号量)就可以。

相关文章:

【linux】进程间通信——system V

system V一、system V介绍二 、共享内存2.1 共享内存的原理2.2 共享内存接口2.2.1 创建共享内存shmget2.2.2 查看IPC资源2.2.3 共享内存的控制shmctl2.2.4 共享内存的关联shmat2.2.5 共享内存的去关联shmdt2.3 进程间通信2.4 共享内存的特性2.5 共享内存的大小三、消息队列3.1 …...

计算机网络的基本组成

计算机网络是由多个计算机、服务器、网络设备&#xff08;如路由器、交换机、集线器等&#xff09;通过各种通信线路&#xff08;如有线、无线、光纤等&#xff09;和协议&#xff08;如TCP/IP、HTTP、FTP等&#xff09;互相连接组成的复杂系统&#xff0c;它们能够在物理层、数…...

【数据结构趣味多】Map和Set

1.概念及场景 Map和set是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例化子类有关。 在此之前&#xff0c;我还接触过直接查询O(N)和二分查询O(logN)&#xff0c;这两个查询有很多不足之出&#xff0c;直接查询的速率太低&#xff0c;而二分查…...

Redis 之企业级解决方案

文章目录一、缓存预热二、缓存雪崩三、缓存击穿四、缓存穿透五、性能指标监控5.1 监控指标5.2 监控方式&#x1f34c;benchmark&#x1f34c;monitor&#x1f34c;slowlog提示&#xff1a;以下是本篇文章正文内容&#xff0c;Redis系列学习将会持续更新 一、缓存预热 1.1 现象…...

雷达实战之射频前端配置说明

在无线通信领域&#xff0c;射频系统主要分为射频前端,以及基带。从发射通路来看&#xff0c;基带完成语音等原始信息通过AD转化等手段转化成基带信号&#xff0c;然后经过调制生成包含跟多有效信息&#xff0c;且适合信道传输的信号&#xff0c;最后通过射频前端将信号发射出去…...

Android SDK删除内置的触宝输入法

问题 Android 8.1.0&#xff0c; 展锐平台。 过CTA认证&#xff0c;内置的触宝输入法会连接网络&#xff0c;且默认就获取到访问网络的权限&#xff0c;没有弹请求窗口访问用户&#xff0c;会导致过不了认证。 预置应用触宝输入法Go版连网未明示&#xff08;开启后&#xff0…...

[202002][Spring 实战][第5版][张卫滨][译]

[202002][Spring 实战][第5版][张卫滨][译] habuma/spring-in-action-5-samples: Home for example code from Spring in Action 5. https://github.com/habuma/spring-in-action-5-samples 第 1 部分 Spring 基础 第 1 章 Spring 起步 1.1 什么是 Spring 1.2 初始化 Spr…...

H5视频上传与播放

背景 需求场景&#xff1a; 后台管理系统&#xff1a; &#xff08;1&#xff09;配置中支持上传视频、上传成功后封面缩略图展示&#xff0c;点击后自动播放视频&#xff1b; &#xff08;2&#xff09;配置中支持上传多个文件&#xff1b; 前台系统&#xff1a; &#…...

通过OpenAI来做机械智能故障诊断-测试(1)

通过OpenAI来做机械智能故障诊断 1. 注册使用2. 使用案例1-介绍故障诊断流程2.1 对话内容2.2 对话小结3. 使用案例2-写一段轴承故障诊断的代码3.1 对话内容3.2 对话小结4. 对话加载Paderborn轴承故障数据集并划分4.1 加载轴承故障数据集并划分第一次测试4.2 第二次加载数据集自…...

ASE40N50SH-ASEMI高压MOS管ASE40N50SH

编辑-Z ASE40N50SH在TO-247封装里的静态漏极源导通电阻&#xff08;RDS(ON)&#xff09;为100mΩ&#xff0c;是一款N沟道高压MOS管。ASE40N50SH的最大脉冲正向电流ISM为160A&#xff0c;零栅极电压漏极电流(IDSS)为1uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。ASE40N…...

MySQL基础命令大全——新手必看

Mysql 是一个流行的开源关系型数据库管理系统&#xff0c;广泛用于各种 Web 应用程序和服务器环境中。Mysql 有很多命令可以使用&#xff0c;以下是 Mysql 基础命令&#xff1a; 1、连接到Mysql服务器&#xff1a; mysql -h hostname -u username -p 其中&#xff0c;"ho…...

sklearn学习-朴素贝叶斯(二)

文章目录一、概率类模型的评估指标1、布里尔分数Brier Score对数似然函数Log Loss二、calibration_curve&#xff1a;校准可靠性曲线三、多项式朴素贝叶斯以及其变化四、伯努利朴素贝叶斯五、改进多项式朴素贝叶斯&#xff1a;补集朴素贝叶斯ComplementNB六、文本分类案例TF-ID…...

MySQL_主从复制读写分离

主从复制 概述 主从复制是指将主数据库的DDL和DML操作通过二进制日志传到从库服务器中&#xff0c;然后在从库上对这些日志重新执行&#xff08;也叫重做&#xff09;&#xff0c;从而使得从库和主库的数据保持同步。 MySQL支持一台主库同时向多台从库进行复制&#xff0c;从…...

shell基础学习

文章目录查看shell解释器写hello world多命令处理执行变量常用系统变量自定义变量撤销变量静态变量变量提升为全局环境变量特殊变量$n$#$* $$?运算符:条件判断比较流程控制语句ifcasefor 循环while 循环read读取控制台输入基本语法:函数系统函数basenamedirname自定义函数shel…...

考虑交叉耦合因素的IPMSM无传感器改进线性自抗扰控制策略

考虑交叉耦合因素的IPMSM无传感器改进线性自抗扰控制策略一级目录二级目录三级目录控制原理ELADRC信号提取龙格贝尔观测器方波注入simulink仿真给定转速&#xff1a;转速环&#xff1a;电流环&#xff1a;一级目录 二级目录 三级目录 首先声明一下&#xff0c;本篇博客是复现…...

2023年全国最新食品安全管理员精选真题及答案5

百分百题库提供食品安全管理员考试试题、食品安全员考试预测题、食品安全管理员考试真题、食品安全员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 41.《中华人民共和国食品安全法》第35条规定&#xff0c;以下&#xff0…...

git 笔记

简介 内容介绍 介绍git怎么管理和实现的 核心概念 文件名-hash-文件内容: 可以通过文件路径定位位置, 也可以通过hash定位位置;快照: 所谓一个快照其实就是一棵树, 叶子结点是一个hash,对应一个文件, 根节点对应文件夹; 一棵树就是一个快照;commit是tree, tree将文件串联, …...

ChatGPT 的盈利潜力:我使用语言模型赚取第一笔钱的个人旅程

使用 Fiverr、Python ChatGPT 和数据科学赚钱的指南。众所周知&#xff0c;ChatGPT 是 12 月发生的互联网突破性事件&#xff0c;几乎每个人都跳过了使用 AI 赚钱的潮流。在本文中&#xff0c;我将分享我是如何使用 ChatGPT 赚到第一笔钱的。本文包括以下主题&#xff1a;回到基…...

计算机网络——问答2023自用

1、高速缓冲存储器Cache的作用&#xff1f; 这种局部存储器介于CPU与主存储器DRAM之间&#xff0c;一般由高速SRAM构成&#xff0c;容量小但速度快&#xff0c;引入它是为了减小或消除CPU与内存之间的速度差异对系统性能带来的影响 &#xff08;Cache可以保存CPU刚用过或循环使…...

【1247. 交换字符使得字符串相同】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 有两个长度相同的字符串 s1 和 s2&#xff0c;且它们其中 只含有 字符 "x" 和 "y"&#xff0c;你需要通过「交换字符」的方式使这两个字符串相同。 每次「交换字符」的时候&…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...