在哪些网站做兼职比较可靠/网络营销期末考试题库
文章目录
- 进程间通信
- 进程通信的意义
- 进程通信的方式
- 1.基于文件的方式
- 匿名管道
- 命名管道
- 2.基于内存的通信方式
- 共享内存
- 验证
- 内核相关的数据结构了解
进程间通信
进程通信的意义
当我们和另一个人打电话时两部手机都是独立的,通过基站传递信号等等复杂的过程就实现了通信。那么进程间是如何进行通信的呢?
我们知道进程是具有独立性的,即使是fork创建的子进程也一样;那么有时我们需要让两个进程进行协同工作,例如一个进程发送信号另一个进程接收信号执行对应的操作,再或者子进程把自己的数据交付给父进程让其处理拦截一些异常信号等等。
由于进程是独立的,是互相看不到对方的数据的,所以想要进行通信就必须看到一份公共资源,这里的公共资源是操作系统提供的一段内存是属于操作系统的。这段内存由于提供的方式不一样会使通信的方式多样性(例如文件struct file方式、队列、数组、原始内存块等等),所以进程间通信是具有一定的成本的。
进程通信的方式
1.基于文件的方式
先来梳理一下当一个进程打开文件时的进程内核角度是怎么样的:
那么fork之后的子进程是什么样的呢?
也就是拷贝了父进程的代码和数据以父进程为模板初始化(浅拷贝),所以子进程和父进程就指向了同一个文件,此时这个文件就是公共资源。
那么我们可以让父子进程在指向同一个文件的前提下,一个负责读缓冲区一个负责往缓冲区写,但不调用底层的读写函数不往文件上刷新,就实现了进程间的通信,这种基于文件的通信方式就叫做管道
(站在操作系统角度下一切皆文件)
所以管道是一个单向通信的通信通道(半双工)
匿名管道
进程是具有独立性的,想让进程间通信其实成本是比较高的,因为必须解决一个问题,创建出一份公共资源(内存、队列、文件、缓冲区)让不同的进程看到,因此操作系统提供了一个函数接口 int pipe(int pipefd[2])
,可以创建一个匿名管道
管道没有名字,只能在具有公共祖先的进程(父进程和子进程,或两个兄弟进程)之间使用,所以叫做匿名管道
头文件 #include <unistd.h> |
---|
参数:pipefd[2]是一个输出型参数,通过这个参数读取到打开的两个fd |
返回值:若成功,返回0;若出错,返回-1并设置errno |
匿名管道实际上是一种固定大小的缓冲区,匿名管道对于管道两端的进程而言就是一个文件,可以看成它是一种特殊的文件,并且只存在于内存中。
如何利用pipe实现通信?
- 父进程利用pipe获取到两个文件描述符
- 父进程fork出子进程,子进程以父进程为模板初始化得到一份相同的struct file* array[ ]
- 一个负责读,一个负责写,但要不能冲突,且要关闭不用的文件描述符接口
示例1:
写端写的慢(或者不写),读端要等写端
管道带有同步机制,读走的数据和写入数据是在管道内部是同步的,且数据一旦被读走,它就从管道中丢弃
写端退出,读端读完pipe内部数据后也退出
示例2:
读端读的慢或读端不读,写端要等读端
现象1:为什么一行读取很多个 hello 你好?
只要匿名管道里还有空间,写的一端就会一直按字节为单位地写,只要管道内还有数据,读的一端就会一直按字节为单位地读,直到返回0表明读到文件末尾,是面向字节流的
字节流:按字节写入,按字节读取
也就是子进程不断在写,而父进程延时读取,读的时候,管道有多少字节读都多少字节,所以可以看到读取很多
现象2:为什么读到65536就不读了?
实际是因为,管道内的大小为64KB(65536/1024 = 64)
所以写端在等读端读取(write置阻塞等待),读取一定的大的字节后才会继续写入
即:
- 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
- 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。
写端写满后,读端至少读取4KB数据才能唤醒写端使写端继续写,同时写说明管道自带同步机制,不会出现新老数据覆盖的问题。
读端关闭,写端也退出产生终止信号并导致子进程退出,只有在管道的读端存在时,向管道中写入数据才有意义
否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号,应用程序可以处理该信号,也可以忽略(默认动作则是应用程序终止)
匿名管道读写规则:
- 读端不读或者读端读的慢,写端要等读端
- 管道的大小是64kb,管道写满时,最少读走4KB,才会继续写入(write挂起等待,暂停写入)
- 写端不写或者写端写的慢,读端要等写端(没有数据时,read挂起等待,暂停读取)
- 读端关闭,写端产生终止信号13(SIGPIPE)直接终止
- 写端关闭,读端读完内部数据后关闭(read返回0,代表读到末尾了)
管道的特点:
-
管道是一个单向通信的通道(半双工)
-
管道是面向字节流的(具体体现在,写端等读端,读端读的时候读取所有写入的字节,按字节写入按字节读取),所以一般双方会规定一些协议
-
管道自带同步机制,原子性写入(读过的数据和写入的数据在管道内部是同步的,所以不会出现读到老数据或新数据覆盖问题)
-
匿名管道是在带有继承关系的进程下完成的
-
管道的生命周期是随着进程的
管道也是文件,只要被一个进程打开,struct file的引用计数就会+1,相关进程退出,引用计数就-1,引用计数为0时,OS会自动关闭管道文件
命名管道
匿名管道只能用于具有继承关系的进程间通信,这就导致有很大局限性,无法在两个不相干的进程间通信。
假如在目录中创建一个真实存在的文件,就可以让不同的进程打开同一份文件了,那么操作系统提供了mkfifo
函数可创建一个命名管道文件
int mkfifo(const char *pathname, mode_t mode);
// 返回值:成功返回0,出错返回-1
头文件#include <sys/stat.h> |
---|
pathname:文件名+路径 |
mode:参数与open 函数中的 mode 相同,表示创建这个文件的权限 |
int main()
{ umask(0); if(mkfifo("./myfifo",0666) < 0) { perror("mkfifo:"); return 1; } return 0;
}
命名管道文件有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中
命名管道文件不会重复创建
命名管道具有匿名管道所有特点,创建好管道文件后,只需要像文件操作一样即可实现不同进程间通信
/*************************************out.c*************************************/#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/wait.h>
int main()
{//创建管道文件umask(0);if(mkfifo("./myfifo",0666) < 0){perror("mkfifo:");return 1;}//打开文件int fd = open("./myfifo",O_RDONLY);if(fd < 0){perror("open:");return 1;}while(1){char buffer[64] = {0};ssize_t ret = read(fd,buffer,sizeof(buffer)-1 ); //期望读取63个但读到末尾就停止,留出一个位置 置一个\0,虽然内核存储没有\0,但是使用printf打印是C的接口,需要置一个\0buffer[ret] = 0; //置\0 if(ret > 0){if(strcmp(buffer,"show") == 0) {if(fork() == 0) //利用子进程替父进程执行命令{execl("/usr/bin/ls","ls","-a","-l",NULL); //进程替换exit(-1); }int status = 0;waitpid(-1,&status,0); //进程等待if(WIFEXITED(status)) //获取进程正常执行退出的退出码printf("exit code:%d\n",WEXITSTATUS(status));else if(WIFSIGNALED(status)) //获取进程退出异常的信号printf("exit signal:%d\n",WTERMSIG(status)); }printf("%s\n",buffer);}else if(ret == 0){printf("out quit...\n");break;}else {perror("read:");break; }}close(fd);return 0;
}
/*************************************put.c*************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>int main()
{//有一个创建管道文件即可,管道文件不可重复创建/* umask(0);if(mkfifo("./myfifo",0666) < 0){perror("mkfifo:");return 1;}
*///推荐系统调用接口,可以减少一些拷贝,如C提供的用户缓冲区int fd = open("./myfifo",O_WRONLY); //只写if(fd < 0){perror("open:");return 1;}//发布命令while(1){char buffer[64] = {0}; //先把要发布的命令保存printf("请输入:");fflush(stdout);ssize_t ret = read(0,buffer,sizeof(buffer)-1); //\0只是C语言规定的,read是系统调用接口,是没有\0这个概念的if(ret > 0){buffer[ret - 1] = 0; //因为输入完要按回车,所以要去除\nwrite(fd,buffer,ret); //发布命令}}close(fd);return 0;
}
现在让out不读,而put一直写:
管道文件不会真的刷新到磁盘,只会在缓冲区中进行读写,可以节省效率
管道总结:
管道是最基本的进程间通讯,它是单向通讯(类似半双工)。它属于内存缓冲区中申请的一份公共资源,是一种特殊的文件,用于连接一个写进程一个读进程。一个进程把数据写入管道,由内核定向的流入另一个读进程。
命名管道:为了保证不同的进程看到同一个文件,必须有名字
匿名管道:文件没有名字,因为他是通过进程继承方式看到同一份资源的,不需要名字标识
读写规则:
- 读端不读或者读端读的慢,写端要等读端
- 管道的大小是64kb,管道写满时,最少读走4KB,才会继续写入(write挂起等待,暂停写入)
- 写端不写或者写端写的慢,读端要等写端(没有数据时,read挂起等待,暂停读取)
- 读端关闭,写端产生终止信号13(SIGPIPE)直接终止
- 写端关闭,读端读完内部数据后关闭(read返回0,代表读到末尾了)
管道的特点:
管道是一个单向通信的通道(半双工)
管道是面向字节流的(具体体现在,写端等读端,读端读的时候读取所有写入的字节,按字节写入按字节读取),所以一般双方会规定一些协议
管道自带同步机制,原子性写入(读过的数据和写入的数据在管道内部是同步的,所以不会出现读到老数据或新数据覆盖问题)
匿名管道是在带有继承关系的进程下完成的
管道的生命周期是随着进程的
管道也是文件,只要是文件被一个进程打开,struct file的引用计数就会+1,相关进程退出,引用计数就-1,引用计数为0时,OS会自动关闭管道文件
2.基于内存的通信方式
共享内存
进程间通信的本质是先让不同的进程看到同一份资源,除了前面介绍的管道通信还有一些其他的方式,systemV标准是在操作系统层面专门为同一主机内的进程间通信设计的一个方案。
systemV常见的通信方式有以下3种:
- 共享内存(本篇介绍)
- 消息队列
- 信号量
共享内存就是让多个进程地址空间在同一个物理内存通过映射的方式在页表中建立的联系
那么我们可以通过某种方式,在内存中申请一块空间,让进程都“挂接“上这块内存,等于让不同的进程看到了同一份资源
那么上述介绍的就是共享内存的原理
那么如何实现申请和挂接呢?若是不用了以后呢?所以可分为以下4个步骤
- 申请内存
- 挂接到内存
- 去除挂接
- 释放内存
这4个步骤都是利用OS提供的接口函数
-
申请内存,需要用到系统提供的
int shmget(key_t key, size_t size, int shmflg);
函数接口key:
key表示共享内存的键值,可以自己填写,也可以由一个算法生成(
key_t ftok(const char *pathname, int proj_id);
)-
生成成功则会返回 路径+id转换的IPC键值
-
生成失败返回 -1
size:
size表示想申请的空间大小,os是按4kb为基准值分配的,不满4kb的会向上调整分配为4kb,所以这里建议按4kb的倍数申请
shmflg:
shmflg可以设置申请方式以及权限,这里介绍两种:
-
IPC_CREAT:单独使用或者不用(即shmflg=0)时表示:申请的内存时的key值若存在,则返回这个内存的shmid号(返回值),若不存在则申请到共享内存
-
IPC_EXCL:IPC_EXCL单独使用没有任何意义,要配合IPC_CREAT使用,
IPC_EXCL|IPC_CREAT
表示:若申请内存的key已经存在则返回错误(-1),若不存在则创建
最后在后面或上8进制形式的权限即可
返回值:
-
申请成功返回一个id号(shmid),类似文件描述符fd,也是一个数组的下标。
(具体这个数组关连的哪些数据结构在后面介绍)
-
申请失败返回-1
shmget使用类似于管道,一个申请,另一个只要保证申请时传入的key是相同就可以获取到申请内存返回的shmid;而ftok函数保证传入的自定义路径和自定义id是相同的就可以获取到相同的key值
而通过运行结果可以反映出,程序结束并不会回收这个内存,所以out再次运行时会申请失败,put再次运行还是可以获取到
在命令行输入
ipcs -m
可以查看共享内存使用情况注意:system V的IPC资源,生命周期是随内核的,只能通过显示释放(命令、system call)或者重启OS
命令行输入
ipcrm -m shmid号
可释放内存 -
-
释放内存,需要用到的
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
函数接口上面介绍了命令行的释放,实际应该像申请动态内存、打开文件那样,要在程序中中做到谁申请谁释放
所以可以用 shmctl控制内存函数
-
成功返回0
-
失败返回-1
这里只介绍删除,在cmd参数传入 IPC_RMID,若cmd传的是IPC_RMID,第三个参数传NULL即可
-
-
进程挂载内存需要用到
void *shmat(int shmid, const void *shmaddr, int shmflg);
接口函数挂接内存的本质是,让进程地址空间与共享内存在页表建立映射关系
shmid:就是申请内存时返回的的shmid,共享内存标识符
shmaddr:指定挂接的地址,一般填NULL即可(真实情况只有OS清楚),
shmflg:表示挂接方式,一般设置0
返回值:
- 挂接成功返回首地址,也就是进程地址空间中对应页表映射的首地址,类似于malloc
- 失败返回-1
-
取消挂载,用到
int shmdt(const void *shmaddr);
函数接口取消挂接的本质是取消进程地址空与共享内存在页表的映射关系
shmaddr:挂载时返回给用户的地址
返回值:
- 成功返回0
- 失败返回-1
验证
/************************************com.h***************************************/
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>/************************************out.c***************************************/
#include "com.h"int main()
{key_t key = ftok(".",0x666);if(key < 0){perror("ftok:");return 1;}//申请共享内存int shmid = shmget(key,4097,IPC_CREAT|IPC_EXCL|0666);if(shmid < 0){perror("shmget");return 1;}printf("key:%#x shmid:%d\n",key,shmid);printf("申请成功\n");sleep(10);//挂接页表-虚拟内存,挂接成功返回起始地址,挂接到页表后,返回映射的虚拟地址中的首地址char* addr =(char*)shmat(shmid,NULL,0);if(addr == NULL){perror("shmat");return 1;}sleep(10);printf("挂接成功\n");//通信#############while(1){sleep(1);printf("%s\n",addr);}//##################//取消挂接,本质是去除进程地址空间与共享内存在页表的映射关系shmdt(addr);sleep(10);printf("取消挂接\n");//释放共享内存shmctl(shmid,IPC_RMID,NULL);printf("释放内存\n");return 0;
}/************************************put.c***************************************/#include "com.h"int main()
{key_t key = ftok(".",0x666);if(key < 0){perror("ftok:");return 1;}//申请共享内存int shmid = shmget(key,4097,IPC_CREAT);//获取if(shmid < 0){perror("shmget");return 1;}printf("key:%#x shmid:%d\n",key,shmid);printf("获取成功\n");sleep(10);//挂接页表-虚拟内存,挂接成功返回起始地址,挂接到页表后,返回映射的虚拟地址中的首地址char* addr =(char*)shmat(shmid,NULL,0);if(addr == NULL){perror("shmat");return 1;}sleep(5);printf("挂接成功\n");//通信############while(1){char ch = 'A';while(ch <= 'Z'){addr[ch - 'A'] = ch; //[0] = Ach++; //CH = Baddr[ch - 'A'] = 0; //[1] = Bsleep(1);}}//#################//取消挂接shmdt(addr);sleep(10);printf("取消挂接\n");//释放内存//谁申请谁释放,这里的内存是out.c申请的/*shmctl(shmid,IPC_RMID,NULL);printf("key:%0x shmid:%d\n",key,shmid);sleep(10);*/return 0;
}
共享内存与管道不同,是一旦申请好直接可以拿到内存的数据,比管道读写数据快,如同malloc一样,并且不提供任何的同步性、原子性,所以这也需要自己设计读写协议
总结:
- 共享内存生命周期随内核
- 进程间通信速度最快(用户->内核,而管道直接调用系统接口下至少要经历 用户->缓冲区->管道)
- 共享内存不提供任何同步机制、原子性等等,是直接可以拿到内存数据
- 共享内存申请时是以页为单位(4kb),不满页的会向上调整成页,但是不会显示出来
内核相关的数据结构了解
共享内存不仅只限于两个进程间的通信,还有可能多个进程进程之间多个内存间通信等等。为了防止这些进程之间都能正确的和对应的共享内存通信,os就需要将共享内存进行管理,只要提到管理就离不开“先描述,在组织“。
怎么描述,怎么组织?
通过查看共享内存部分内核源码发现,在申请共享内存时会有结构体来记录申请时时的所有详细信息,如创建时间、申请大小、key值等等
再查看消息队列、信号量的在内核中的结构体
发现它们都有一个共同点,第一个成员都是 struct ipc_perm
所以在打印shmid时发现其好像是呈数组下标形式,其实正是由于IPC(通信)的多样性,内核的IPC资源结构类型不一样,为了方便管理,所以在每个资源的结构的第一个成员都设置成相同的。
而struct ipc_perm
是记录一些比较关键的信息如key值,那么这里也可以类似struct file* array[]一样有一个ipc_perm指针数组,存每个IPC资源的中的ipc_perm,所以shmid的作用就等同于文件描述符fd的作用。
( ipc_perm是第一个成员,第一个成员的地址也是IPC的首地址,可以通过强转类型的方式将每个IPC强转成ipc_perm,再利用ipc_prem* 接收,就可以拿到每个IPC中的ipc_prem了,类似C++中的切片 )
相关文章:

Linux操作系统学习(进程间通信)
文章目录进程间通信进程通信的意义进程通信的方式1.基于文件的方式匿名管道命名管道2.基于内存的通信方式共享内存验证内核相关的数据结构了解进程间通信 进程通信的意义 当我们和另一个人打电话时两部手机都是独立的,通过基站传递信号等等复杂的过程就实现了通…...

单目标追踪——【相关滤波】C-COT原理与ECO基于C-COT的改进
目录C-COT:Continuous Convolution Operator Tracker文章侧重点连续卷积算子目标追踪框架初始化过滤器:追踪流程ECO文章侧重点因式卷积因子生成采样空间模型模型更新策略论文链接:C-COT:Beyond Correlation Filters: Learning Con…...

C++中栈是如何实现,以及常用的栈函数都有哪些
什么是栈? 栈 是一种特殊的数据结构,它是一种按照 Last-In-First-Out (LIFO) 访问模式存储和访问数据的特殊结构。 换句话说,栈中的最后一个元素将成为最先出栈的元素,这也意味着新增加的元素在栈的顶部,而出栈的元素…...

我就不信你还不懂HashSet/HashMap的底层原理
💥注💥 💗阅读本博客需备的前置知识如下💗 🌟数据结构常识🌟👉1️⃣八种数据结构快速扫盲🌟Java集合常识🌟👉2️⃣Java单列集合扫盲 ⭐️本博客知识点收录于…...

Qt中调用gtest进行单元测试及生成覆盖率报告
一.环境配置 googletest地址:https://github.com/google/googletest 我下载的是1.12.1,这是最后一个支持C++11的版本。 首先编译gtest,在windows上的编译方式和编译gRPC一模一样,详见Qt中调用gRPC,编译完了会生成几个静态库,如下图所示 本文主要用到了libgtest.a 下载ms…...

ChatGPT vs Bard 背后的技术对比分析和未来发展趋势
ChatGPT vs Bard 背后的技术对比分析和未来发展趋势 目录 ChatGPT vs Bard 背后的技术对比分析和未来发展趋势...

搜索引擎的设计与实现
技术:Java、JSP等摘要:随着互联网的快速发展,网络上的数据也随着爆炸式地增长。如何最快速筛选出对我们有用的信息成了主要问题。搜索引擎是指根据一定的策略、运用特定的计算机程序从互联网上搜集信息,在对信息进行组织和处理后&…...

动态规划之买卖股票问题
🌈🌈😄😄 欢迎来到茶色岛独家岛屿,本期将为大家揭晓动态规划之买卖股票问题 ,做好准备了么,那么开始吧。 🌲🌲🐴🐴 动态规划算法本质上就是穷举…...

MySQL学习笔记之子查询
自连接方式 自连接就是表A连接表A,通过where关键字实现,比如查询工资比Abel高的员工信息: SELECTe2.last_name,e2.salary FROMemployees e1,employees e2 WHEREe1.last_name "Abel" AND e2.salary > e1.salary;子查询 亦称为…...

HCIP-5OSPF域内域间外部路由学习笔记
1、OSPF区域 每个区域都维护一个独立的LSDB。 Area 0是骨干区域,其他区域都必须与此区域相连。 划分OSPF区域可以缩小路由器的LSDB规模,减少网络流量。 区域内的详细拓扑信息不向其他区域发送,区域间传递的是抽象的路由信息,而不…...

【编程实践】简单是好软件的关键:Simplicity is key to good software
Simplicity is key to good software 简单是好软件的关键 目录 Simplicity is key to good software简单是好软件的关键 Complexity is tempting. 复杂性很诱人。 The smallest way to create value创造价值的最小方法 Simple 简单的 Complexity is tempting. 复杂性很诱人…...

Python|贪心|数组|二分查找|贪心|数学|树|二叉搜索树|在排序数组中查找元素的第一个和最后一个位置|计数质数 |将有序数组转换为二叉搜索树
1、在排序数组中查找元素的第一个和最后一个位置(数组,二分查找) 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target,返回 […...

操作系统——15.FCFS、SJF、HRRN调度算法
这节我们来看一下进程调度的FCFS、SJF、HRRN调度算法 目录 1.概述 2.先来先服务算法(FCFS,First Come First Serve) 3.短作业优先算法(SJF,Shortest Job First) 4.高响应比优先算法(HRRN&…...

如何防止用户打开浏览器开发者工具?
大家好,我是前端西瓜哥。作为一名前端开发,在浏览一些网页时,有时会在意一些交互效果的实现,会打开开发者工具查看源码实现。 但有些网站做了防窥探处理,打开开发者工具后,会无法再正常进行网页的操作。 …...

C语言-基础了解-12-C数组
C数组 一、C数组 C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。 数组的声明并不是声明一个个单独的变量,比如 runoob0、runoob1、…、runoo…...

RocksDB 架构
文章目录1、RocksDB 摘要1.1、RocksDB 特点1.2、基本接口1.3、编译2、LSM - Tree2.1、Memtable2.2、WAL2.3、SST2.4、BlockCache3、读写流程3.1、读取流程3.2、写入流程4、LSM-Tree 放大问题4.1、放大问题4.2、compactionRocksDB 是 Facebook 针对高性能磁盘开发开源的嵌入式持…...

MVVM和MVC的区别
首先,MVVM 和 MVC 都是一种设计模式MVCM(Model): 模型层。 用于处理应用程序数据逻辑的部分,模型对象负责在数据库中存取数据V (View): 视图层。 处理数据显示的部分 ,视…...

c++11 标准模板(STL)(std::unordered_map)(三)
定义于头文件 <unordered_map> template< class Key, class T, class Hash std::hash<Key>, class KeyEqual std::equal_to<Key>, class Allocator std::allocator< std::pair<const Key, T> > > class unordered…...

OpenGL环境配置
方法一:1.下载GLFW点击GLFW跳转2.下载后解压3.下载glad,解压后4.用vs2019新建Cmake项目5.在新建的Cmake项目下建立depend文件夹在depend里放置我们下载解压的glad和glfw-3.3.8.bin.WIN646.项目中可以看到我们加进来的文件7.编写我们项目的CMakeLists.txt…...

SpringCloud之 Eureka注册中心
文章目录Eureka注册中心一、服务注册与发现1.1 依赖导入①父工程 SpringCloud 版本管理②Eureka 服务端依赖③Eureka 客户端依赖1.2 服务注册①创建 Eureka 服务端的主类②设置 Eureka 服务端的配置文件③设置 Eureka 客户端的配置文件④关闭自我保护机制1.3 服务发现①远程调用…...

Linux入门篇-用户管理
简介 linux基本的用户管理。 ⽤户的管理(切换到root) ⽤户的添加(useradd) ⽤户的删除(userdel) ⽤户的修改(usermod) ⽤户的查看(查看/etc/passwd) id⽤户组的管理(切换到root) …...

G. Special Permutation(构造)
1、题目 G. Special Permutation 这道题的意思是给我们从111到nnn的排列,然后我们对这个排列的顺序上进行调换,需要满足的条件是任意两个相邻元素的绝对值的差满足条件:2≤∣pi−pi1∣≤42\leq |p_i-p_{i 1}|\leq 42≤∣pi−pi1∣≤4 …...

QML动态对象管理
QML中有多种方式来动态创建和管理QML对象: Loader (加载器)Repeater(复制器)ListView,GridWiew,PethView(视图) (之后会介绍)使用加载器ÿ…...

cmake入门03 -自定义find外部库
自定义检测外部库使用pkg-config查找库搜索.pc配置文件cmake函数链接到库自定义find库检测外部库的便捷方法:使用CMake自带的find-module使用<package>Config.cmake, <package>ConfigVersion.cmake和<package>Targets.cmake。这些文件由软件商提供…...

Dubbo源码解析-——服务导出
前言 在之前我们讲过Spring和Dubbo的集成,我们在服务上标注了DubboService的注解,然后最终Dubbo会调用到ServiceBean#export方法中,本次我们就来剖析下服务导出的全流程。 一、前置回顾 由于ServiceBean实现了ApplicationListener接口&…...

vue+django+neo4j 基于知识图谱红楼梦问答系统
vuedjangoneo4j 基于知识图谱红楼梦问答系统 项目背景 知识图谱是一种以图谱形式描述客观世界中存在的各种实体、概念及其关系的技术, 广泛应用于智能搜索、自动问答和决策支持等领域. 可视分析技术可以将抽象的知识图谱映射为图形元素, 帮助用户直观地感知和分析数据, 从而提…...

2023年全国最新食品安全管理员精选真题及答案13
百分百题库提供食品安全管理员考试试题、食品安全员考试预测题、食品安全管理员考试真题、食品安全员证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 121.关于食品召回的说法,以下表述不正确的是(&am…...

Keychron K7 Pro 轻薄矮轴机械键盘开箱体验
文章目录1. 拆箱2. 零件3. 外观4. 声音5. 特点5.1 有线 / 无线5.2 RGB背光5.3 轻薄5.4 mac / win / iphone 切换5.5 人体工程学支持5.6 扁平双射PBT键帽5.7 重新设计的稳定器5.8 扁平Gateron(佳达隆)轴体5.9 热插拔5.10 支持 QMK / VIA 改键6. 对比6.1 K7 与 K7 Pro 参数对比6.…...

加油站ai视觉识别系统 yolov7
加油站ai视觉识别系统通过yolov7网络模型深度学习,加油站ai视觉识别算法对现场画面中人员打电话抽烟等违规行为,还有现场出现明火烟雾等危险状态。除此之外,模型算法还可以对卸油时灭火器未正确摆放、人员离岗不在现场、卸油过程静电释放时间…...

【电子学会】2022年12月图形化二级 -- 绘制风车
绘制风车 1. 准备工作 (1)隐藏默认的小猫角色; (2)选择背景:“Xy-grid”。 2. 功能实现 (1)小猫角色的初始位置为(x:0,y:0); (2)线条粗细为…...