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

深圳网站制作公司方案/seo建站技术

深圳网站制作公司方案,seo建站技术,abplayer wordpress,网站开发网页上传和网页发布目录 一、Linux中的信号 1、Linux中的信号 2、进程对信号的处理 3、信号的释义 二、信号的捕捉 1、信号的捕捉signal() 2、信号的捕捉sigaction() 三、信号如何产生? 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 2、rais…


目录

一、Linux中的信号

1、Linux中的信号

2、进程对信号的处理

3、信号的释义

二、信号的捕捉

1、信号的捕捉signal()

2、信号的捕捉sigaction()

三、信号如何产生?

1、kill()用户调用kill向操作系统发送信号

通过命令行参数模仿写一个kill命令

2、raise()进程自己给自己发任意信号(实际上是操作系统->进程)

3、abort()进程自己给自己发6号信号

4、硬件异常产生信号

4.1八号信号SIGFPE(除零错误可引发)

4.2十一号信号SIGSEGV(段错误可引发)

5、软件条件产生异常

5.1十三号信号SIGPIPE(匿名管道读端关闭,写端收到该信号)

5.2十四号信号SIGALRM(定时器)

6、信号相关问答

四、进程退出时的核心转储

1、核心转储的定义

2、核心转储的意义

五、信号的保存(位图结构)

1、相关概念铺垫

2、信号在内核中的表示

六、信号的处理

1、再谈进程地址空间

1.1用户态->内核态

1.2进程如何从用户态切换至内核态并执行内核代码

2、信号的捕捉流程

3、sigset_t信号集(调库,用于处理block和pending位图中的01)

4、sigprocmask(调用该函数可读取或更改阻塞信号集)

5、sigpending(获取当前进程的pending信号集)

6、屏蔽信号并实时打印pending位图(运用上方三个接口)

七、可重入函数

八、volatile关键字

九、SIGCHLD信号


一、Linux中的信号

1、Linux中的信号

使用kill -l查看所有信号。使用信号时,可使用信号编号或它的宏。

1、Linux中信号共有61个,没有0、32、33号信号。

2、【1,31】号信号称为普通信号,【34,64】号信号称为实时信号。

以普通信号为例,进程task_struct结构体中存在unsigned int signal变量用以存放普通信号。(32个比特位中使用0/1存储、区分31个信号——位图结构)

那么发送信号就是修改进程task_struct结构体中的信号位图。当然,有权限改动进程PCB的,也只有操作系统了。

2、进程对信号的处理

1、进程本身是程序员编写的属性和逻辑的集合;

2、信号可以随时产生(异步)。但是进程当前可能正在处理更为重要的事情,当信号到来时,进程不一定会马上处理这个信号;

3、所以进程自身必须要有对信号的保存能力;

4、进程在处理信号时(信号被捕捉),一般有三种动作:默认、自定义、忽略。

3、信号的释义

man 7 signal查看信号详细信息的命令

Trem:正常结束;Core:异常退出,可以使用核心转储功能定位错误,见本文第四节;Ign:内核级忽略。

2)SIGINT  终止信号,即键盘输入ctrl+c
3)SIGQUIT 终止信号,即键盘输入ctrl+\
6)SIGABRT 终止信号  调用abort即可收到该信号
8)SIGFPE  终止信号  除0错误即可收到该信号
11)SIGSEGV 终止信号 段错误即可收到该信号
13)SIGPIPE 终止信号 匿名管道读端关闭,写端即可收到该信号
14)SIGALRM 终止信号 alarm()函数(定时器)
17)SIGCHLD 内核级忽略信号 子进程退出时会向父进程发送该信号
18)SIGURG 继续进程(进程切换至后台运行,通过9号信号杀掉)
19)SIGSTOP 暂停进程

可以发现,有挺多信号的功能都是一样的。这是因为不同的信号,可以代表发生了不同的事件,但处理结果可以一致。

二、信号的捕捉

1、信号的捕捉signal()

SIGNAL(2) 
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);//signum:被捕捉的信号编号;handler:对指定的信号设置自定义动作
handler设置为SIG_DFL表示信号默认处理方式,SIG_ING设置为忽略处理
#include <iostream>
#include <unistd.h>
#include <signal.h>
void hancler(int signo)
{//这里写自定义内容,捕获到signo信号后即可执行自定义代码std::cout<<"进程捕捉到信号"<<signo<<std::endl;
}
int main()
{signal(2,hancler);//外部需要对该进程发送信号while(1){std::cout<<getpid()<<std::endl;sleep(1);}return 0;
}

外部需要对该进程发送信号,才能被signal接口捕捉。上面例子中,外部发送kill -2 PID或者键盘ctrl+c都行。

当捕捉到指定信号后,将会执行自定义函数。可用于信号功能的替换。

9号和19号信号无法被捕捉kill -9乱杀进程,kill -19暂停进程。

2、信号的捕捉sigaction()

SIGACTION(2)    
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
signum:信号;act:结构体对象;oldact:输出型参数,记录原来的act对象
struct sigaction {void (*sa_handler)(int);//回调方法void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;//阻塞信号集int sa_flags;void (*sa_restorer)(void);//用于支持旧版本的sigaction函数的信号处理函数地址,一般不使用。
};
Sigaction()在成功时返回0; 在错误时返回 -1,并设置 errno。

当一个信号正在被递达执行期间,pending位图由1置0,同时该信号将被阻塞。

如果这时再接收到这个信号,发现该信号被阻塞,同时pending位图由0置1,保存这个信号。

若同一时间再接收到该信号,由于pending已存满,多余的该信号将被丢失。

当首个信号被捕捉完毕,操作系统会立即解除对该信号的屏蔽,因为pending位图对应的比特位是1,所以立即执行新的捕捉动作,同时pending位图该信号位由1清零。

这就是上图执行结果出现两次2号信号捕捉的原因。

三、信号如何产生?

1、kill()用户调用kill向操作系统发送信号

通过命令行参数模仿写一个kill命令

有一个系统调用kill,用户使用kill函数让操作系统向进程发送信号。

KILL(2) 
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);//pid:目标进程的pid。sig:几号信号
成功时(至少发送了一个信号) ,返回零。出现错误时,返回 -1设置errno

mysignal.cc

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string>
void Usage(const std::string& proc)
{std::cout<<"Usige:"<<getpid()<< "Signno\n"<<std::endl;
}int main(int argc,char* argv[])//运行main函数时,需要先进行传参
{if(argc!=3)//如果传入main函数的参数个数不为3{Usage(argv[0]);exit(1);}pid_t pid=atoi(argv[1]);//获取第一个命令行参数,作为pidint signo=atoi(argv[2]);//获取第二个命令行参数,作为signoint n=kill(pid,signo);//需要发送信号的进程/发送几号信号if(n==-1)//kill()失败返回-1{perror("kill");}while(1){std::cout<<getpid()<<std::endl;sleep(1);}return 0;
}

2、test.cc

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
int main()
{while(1){std::cout<<"这是一个正在运行的进程"<<getpid()<<std::endl;sleep(1);}return 0;
}

2、raise()进程自己给自己发任意信号(实际上是操作系统->进程)

RAISE(3)
#include <signal.h>
int raise(int sig);//sig:信号编号
raise()在成功时返回0,在失败时返回非0。

raise(signo)等于kill(getpid,signo);

//当计数器运行到5时,进程会因3号进程退出
int main(int argc,char* argv[])//运行main函数时,需要先进行传参
{int cnt=0;while(cnt<=10){std::cout<<cnt++<<std::endl;sleep(1);if(cnt>=5){raise(3);}}return 0;
}

3、abort()进程自己给自己发6号信号

ABORT(3)
#include <stdlib.h>
void abort(void);
函数 abort()永远不会返回

abort()等于kill(getpid,SIGABRT);

4、硬件异常产生信号

硬件异常指非人为调用系统接口等行为,因软件问题造成的硬件发生异常。操作系统通过获知对应硬件的状态,即可向对应进程发送指定信号。

4.1八号信号SIGFPE(除零错误可引发)

例如出现除0错误,操作系统将会发送8号信号SIGFPE。

此时使用signal()捕捉这个信号,就会发现8号信号一直在被捕捉。这是因为状态寄存器是由CPU进行维护的,当8号信号被捕捉,进程并没有退出,根据时间片轮转,当进程被切换/剥离至CPU时,会读取和保存当前寄存器的上下文信息,所以我们就看到了8号信号被死循环捕捉。

4.2十一号信号SIGSEGV(段错误可引发)

5、软件条件产生异常

5.1十三号信号SIGPIPE(匿名管道读端关闭,写端收到该信号)

例如匿名管道读端关闭,操作系统会向写端发送13号信号SIGPIPE终止写端。

5.2十四号信号SIGALRM(定时器)

设置alarm函数是在告诉操作系统,将在设定的时间到来时,向进程发送14号信号终止进程。

ALARM(2)  
#include <unistd.h>
unsigned int alarm(unsigned int seconds);//seconds延时几秒
返回值为定时器剩余的秒数(可能会被提前唤醒)
alarm(0)表示取消之前设定的闹钟
//设置一个cnt,用于测试代码在指定时间跑了多少
void hancler(int signo)
{//这里写自定义内容,捕获到signo信号后即可执行自定义代码std::cout<<"进程捕捉到信号"<<signo<<" "<<cnt<<std::endl;//检测到5秒后cnt为多少alarm(5);//循环捕捉闹钟
}
int main()
{signal(14,hancler);alarm(1);//定时1秒alarm(5);//定义新的闹钟,旧闹钟会失效哦while(1){cnt++;}return 0;
}

闹钟是由软件实现的。任何一个进程,都可以通过alarm函数设定闹钟,所以操作系统需要通过先描述再组织的方式管理这些闹钟。

6、信号相关问答

所有信号产生,最终都要有操作系统来进行执行,因为操作系统是进程的管理者 。

信号的处理是否是立即处理的?见下文~

信号如果没有被立即处理,那么信号将被保存至pending位图中

一个进程在没有收到信号的时候,能否知道,自己应该对合法信号作何处理呢? 能,程序员写好了对应信号的处理方式(你没走人行道但你知道红灯停,绿灯行)

如何理解OS向进程发送信号?能否描述一下完整的发送处理过程?操作系统直接修改进程pcb中的信号位图。

四、进程退出时的核心转储

信号旁边写着Core的信号,都可以使用核心转储功能。

1、核心转储的定义

核心转储:当进程出现异常时,将进程在对应时刻的有效数据由内存存储至磁盘。

云服务器默认关闭了核心转储。在终端输入ulimit -a显示操作系统各项资源上限;使用ulimit -c 1000允许操作系统最大设置1000个block大小的数据块。

2、核心转储的意义

将程序异常的原因转储至磁盘,支持后续调试。

五、信号的保存(位图结构)

1、相关概念铺垫

1、信号递达(Delivery) :实际执行信号的处理动作;

2、信号未决(Pending):信号从产生到递达之间的状态

3、进程可以选择阻塞 (Block )某个信号。

4、信号被阻塞时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.

5、阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

2、信号在内核中的表示

例如signal捕获信号的流程就是通过signo编号修改handler[signo]中的函数指针指向用户自定义的信号处理方法。当收到信号时,将pending位图中对应的比特位修改为1,若block位图中没有阻塞该信号,该信号被递达时就会执行该信号的处理方法。

对于普通信号,pending位图同时间只能保存一次同个信号,若该信号处于未递达状态,后续再次收到该信号将无法被保存(丢失)。

六、信号的处理

1、再谈进程地址空间

博主首篇进程地址空间传送门:【Linux】进程地址空间

1.1用户态->内核态

1.2进程如何从用户态切换至内核态并执行内核代码

每个进程的虚拟地址空间中有一块1G大小的内核空间,通过内核级页表映射的方式找到物理内存中内核代码进行执行。

由于内核级页表中对应物理地址的映射关系是一样的,所以每个进程都可以使用相同的内核级页表,无论进程如何切换,均可使用同一张内核级页表进行映射调用。

在进行用户态->内核态的切换过程中,首先通过CR3寄存器将进程状态由用户态修改为内核态(陷入内核),在本进程的内核空间中找到物理内存中的内核代码进行执行,执行完毕后将结果返回给进程。

2、信号的捕捉流程

信号的自定义捕捉:信号在产生的时候,不会被立刻处理,而是从内核态返回用户态的时候,对信号进行处理。

进程首先因为中断、异常、系统调用陷入内核,以内核态的身份运行内核代码,通过进程控制块中的信号位图分析当前信号的处理方式。

 若为自定义处理,则需要进程回到用户态去执行用户设定的handler方法。为什么进程不能以内核态的身份直接执行handler方法?这是因为进程处于内核态,权限非常高,操作系统是没有能力识别代码的逻辑的,若handler被人为植入恶意代码,原先部分没有权限的代码因为执行身份的变化而被提权,所以操作系统必须让进程先回到用户态,降低进程的权限。

执行完handler方法后,进程需要重新回到内核态去执行一些系统调用,才能回退回用户态。

3、sigset_t信号集(调库,用于处理block和pending位图中的01)

每个信号只有一个bit的未决/阻塞标志,非0即1,不记录该信号产生了多少次。

因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集。这个类型可以表示每个信号的“有效”或“无效”状态。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。

#include <signal.h>
函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。
int sigemptyset(sigset_t *set);
函数sigfifillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。 
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

在使用sigset_ t类型的变量之前,一定要调用sigemptyset或sigfifillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。

这四个函数都是成功返回0,出错返回-1。sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。

4、sigprocmask(调用该函数可读取或更改阻塞信号集)

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1

如果oset是非空指针,则读取进程的当前信号屏蔽字并通过oset参数传出。

如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。

如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

how:如何屏蔽信号集

SIG_BLOCK

set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask | set

SIG_UNBLOCK

set包含了我们希望从当前信号屏蔽字解除阻塞的信号,相当于mask=mask&~set

SIG_SETMASK

设置当前信号屏蔽字为set所指向的值,相当于mask=set

如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。没有手动捕捉的话,一般信号都是终止的,所以递达了,进程大概率也就寄了。

5、sigpending(获取当前进程的pending信号集)

SIGPENDING(2)
#include <signal.h>
int sigpending(sigset_t *set);//set:输出型参数,输出当前进程pending位图
sigending()在成功时返回0,在错误时返回-1。在发生错误时,将 errno 设置。

6、屏蔽信号并实时打印pending位图(运用上方三个接口)

默认情况所有的信号是不被阻塞的,如果一个信号被屏蔽了,那么这个信号不会被递达。

#include <iostream>
#include <vector>
#include <signal.h>
#include <unistd.h>// #define BLOCK_SIGNAL 2
#define MAX_SIGNUM 31using namespace std;// static vector<int> sigarr = {2,3};
static vector<int> sigarr = {2};static void show_pending(const sigset_t &pending)
{for(int signo = MAX_SIGNUM; signo >= 1; signo--){if(sigismember(&pending, signo)){cout << "1";}else cout << "0";}cout << "\n";
}static void myhandler(int signo)
{cout << signo << " 号信号已经被递达!!" << endl;
}int main()
{for(const auto &sig : sigarr) signal(sig, myhandler);// 1. 先尝试屏蔽指定的信号sigset_t block, oblock, pending;// 1.1 初始化sigemptyset(&block);sigemptyset(&oblock);sigemptyset(&pending);// 1.2 添加要屏蔽的信号for(const auto &sig : sigarr) sigaddset(&block, sig);// 1.3 开始屏蔽,设置进内核(进程)sigprocmask(SIG_SETMASK, &block, &oblock);// 2. 遍历打印pengding信号集int cnt = 10;while(true){// 2.1 初始化sigemptyset(&pending);// 2.2 获取它sigpending(&pending);// 2.3 打印它show_pending(pending);// 3. 慢一点sleep(1);if(cnt-- == 0){sigprocmask(SIG_SETMASK, &oblock, &block); // 一旦对特定信号进行解除屏蔽,一般OS要至少立马递达一个信号!cout << "恢复对信号的屏蔽,不屏蔽任何信号\n";}}
}

七、可重入函数

main函数调用insert函数向一个链表head中插入节点P1,插入操作分为两步,刚执行完第一句代码,此时硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作执行完毕后,sighandler返回内核态,再次回到用户态就从main函数继续执行刚才剩余的代码。结果是,main函数和sighandler先后向链表中插入两个节点,而最后只有P1真正插入链表中,P2这个节点谁都找不到了。发生内存泄漏

像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱。像这样的函数称为不可重入函数,反之, 如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数。

不可重入函数:调用了malloc或free,因为malloc也是用全局链表来管理堆的。 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。

八、volatile关键字

优化后,通过信号自定义方法handler修改全局q,但是程序不会退出。

O3优化时:编译器认为q在main执行流中没有被修改,所以编译器对q做了优化,直接将q放在了寄存器中,这样后续执行时就不用再去内存中读取q了,提高了程序运行效率。虽然handler中修改了内存中的q,但是寄存器中的q值一直是1(寄存器中的q值是临时值,操作系统没有对其进行修改),所以会发生上图效果。

解决方法:给q加volatile关键字,让q通过内存读取而不是寄存器,保持变量q的内存可见性。

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
volatile int q=1;//保持内存可见性
void handler(int signo)
{q=0;
}
int main()
{signal(2,handler);while(q!=0);return 0;
}

当程序结果与预期偏离时,可以尝试使用volatile关键字,万一就是编译器过度优化造成的程序逻辑异常呢?

九、SIGCHLD信号

1、子进程退出,会向父进程发送17号信号SIGCHLD;

2、由于UNIX 的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不会产生僵尸进程,也不会通知父进程。

//忽略子进程发出的17号信号
signal(SIGCHLD,SIG_IGN);
sigaction(SIGCHLD,act,oldact);//act中忽略17号信号

系统默认的忽略动作和用户用signal/sigaction函数自定义的忽略 通常是没有区别的,但这里是一个特例。

虽然信号SIGCHID的默认动作也是忽略,但这个忽略是实实在在的无视了这个信号;我们手动在handler方法中使用SIG_IGN,子进程退出时发送给父进程的信号将会被父进程忽略,但子进程会被操作系统回收,这就是区别所在。

相关文章:

【Linux】信号+再谈进程地址空间

目录 一、Linux中的信号 1、Linux中的信号 2、进程对信号的处理 3、信号的释义 二、信号的捕捉 1、信号的捕捉signal() 2、信号的捕捉sigaction() 三、信号如何产生&#xff1f; 1、kill()用户调用kill向操作系统发送信号 通过命令行参数模仿写一个kill命令 2、rais…...

C++回顾(二十一)—— list容器

21.1 list概述 list是一个双向链表容器&#xff0c;可高效地进行插入删除元素。list不可以随机存取元素&#xff0c;所以不支持at.(pos)函数与[]操作符。It(ok) it5(err)需要添加头文件&#xff1a;#include <list> 21.2 list构造 &#xff08;1&#xff09;默认构造…...

爱国者一体机电脑蓝屏怎么U盘重装系统教学?

爱国者一体机电脑蓝屏怎么U盘重装系统教学&#xff1f;有用户使用的爱国者一体机电脑开机了之后突然变成了蓝屏的了。而且无法继续使用了&#xff0c;那么遇到这样的蓝屏问题怎么去进行系统的重装呢&#xff1f;一起来看看以下的U盘重装系统教学吧。 准备工作&#xff1a; 1、U…...

Vue学习笔记(9)

9.1 axios 9.1.1 概述 Axios是一个流行的基于Promise的HTTP客户端&#xff0c;用于在浏览器和Node中发送HTTP请求。它可以用于处理各种请求类型&#xff0c;例如GET&#xff0c;POST等。Axios可以很容易地与现代前端框架和库集成&#xff0c;例如React&#xff0c;Vue等。 A…...

中值滤波+Matlab仿真+频域响应分析

中值滤波 文章目录中值滤波理解中值滤波的过程Matlab 实现实际应用频域分析中值滤波是一种滤波算法&#xff0c;其目的是去除信号中的噪声&#xff0c;而不会对信号本身造成太大的影响。它的原理非常简单&#xff1a;对于一个给定的窗口大小&#xff0c;将窗口内的数值排序&…...

自然语言处理中数据增强(Data Augmentation)技术最全盘点

与“计算机视觉”中使用图像数据增强的标准做法不同&#xff0c;在NLP中&#xff0c;文本数据的增强非常少见。这是因为对图像的琐碎操作&#xff08;例如将图像旋转几度或将其转换为灰度&#xff09;不会改变其语义。语义上不变的转换的存在是使增强成为Computer Vision研究中…...

PINN解偏微分方程实例1

PINN解偏微分方程实例11. PINN简介2. 偏微分方程实例3. 基于pytorch实现代码4. 数值解参考资料1. PINN简介 PINN是一种利用神经网络求解偏微分方程的方法&#xff0c;其计算流程图如下图所示&#xff0c;这里以偏微分方程(1)为例。 ∂u∂tu∂u∂xv∂2u∂x2\begin{align} \frac{…...

【python 基础篇 十二】python的函数-------函数生成器

目录1.生成器基本概念2.生成器的创建方式3.生成器的输出方式4.send()方法5.关闭生成器6.注意事项1.生成器基本概念 是一个特色的迭代器&#xff08;迭代器的抽象层级更高&#xff09;所以拥有迭代器的特性 惰性计算数据 节省内存 ----就是不是立马生成所有数据&#xff0c;而是…...

elasticsearch全解 (待续)

目录elasticsearchELK技术栈Lucene与Elasticsearch关系为什么不是其他搜索技术&#xff1f;Elasticsearch核心概念Cluster&#xff1a;集群Node&#xff1a;节点Shard&#xff1a;分片Replia&#xff1a;副本全文检索倒排索引正向和倒排es的一些概念文档和字段索引和映射mysql与…...

springboot2集成knife4j

springboot2集成knife4j springboot2集成knife4j 环境说明集成knife4j 第一步&#xff1a;引入依赖第二步&#xff1a;编写配置类第三步&#xff1a;测试一下 第一小步&#xff1a;编写controller第二小步&#xff1a;启动项目&#xff0c;访问api文档 相关资料 环境说明 …...

Qt 性能优化:CPU占有率高的现象和解决办法

一、前言 在最近的项目中&#xff0c;发现执行 Qt 程序时&#xff0c;有些情况下的 CPU 占用率奇高&#xff0c;最高高达 100%。项目跑在嵌入式板子上&#xff0c;最开始使用 EGLFS 插件&#xff0c;但是由于板子没有单独的鼠标层&#xff0c;导致鼠标移动起来卡顿&#xff0c…...

MySQL专题(学会就毕业)

MySQL专题0.准备sql设计一张员工信息表&#xff0c;要求如下&#xff1a;编号&#xff08;纯数字&#xff09;员工工号 (字符串类型&#xff0c;长度不超过10位)员工姓名&#xff08;字符串类型&#xff0c;长度不超过10位&#xff09;性别&#xff08;男/女&#xff0c;存储一…...

Java高级技术:单元测试、反射、注解

目录 单元测试 单元测试概述 单元测试快速入门 单元测试常用注解 反射 反射概述 反射获取类对象 反射获取构造器对象 反射获取成员变量对象 反射获取方法对象 反射的作用-绕过编译阶段为集合添加数据 反射的作用-通用框架的底层原理 注解 注解概述 自定义注解 …...

C语言初识

#include <stdio.h>//这种写法是过时的写法 void main() {}//int是整型的意思 //main前面的int表示main函数调用后返回一个整型值 int main() {return 0; }int main() { //主函数--程序的入口--main函数有且仅有一个//在这里完成任务//在屏幕伤输出hello world//函数-pri…...

Cadence Allegro 导出Etch Length by Layer Report报告详解

⏪《上一篇》   🏡《上级目录》   ⏩《下一篇》 目录 1,概述2,Etch Length by Layer Report作用3,Etch Length by Layer Report示例4,Etch Length by Layer Report导出方法4.2,方法14.2,方法2B站关注“硬小二”浏览更多演示视频...

无监督对比学习(CL)最新必读经典论文整理分享

对比自监督学习技术是一种很有前途的方法&#xff0c;它通过学习对使两种事物相似或不同的东西进行编码来构建表示。Contrastive learning有很多文章介绍&#xff0c;区别于生成式的自监督方法&#xff0c;如AutoEncoder通过重建输入信号获取中间表示&#xff0c;Contrastive M…...

最长回文子串【Java实现】

题目描述 现有一个字符串s&#xff0c;求s的最长回文子串的长度 输入描述 一个字符串s&#xff0c;仅由小写字母组成&#xff0c;长度不超过100 输出描述 输出一个整数&#xff0c;表示最长回文子串的长度 样例 输入 lozjujzve输出 // 最长公共子串为zjujz&#xff0c;长度为…...

LeetCode 438. Find All Anagrams in a String

LeetCode 438. Find All Anagrams in a String 题目描述 Given two strings s and p, return an array of all the start indices of p’s anagrams in s. You may return the answer in any order. An Anagram is a word or phrase formed by rearranging the letters of a…...

MyBatis-1:基础概念+环境配置

什么是MyBatis&#xff1f;MyBatis是一款优秀的持久层框架&#xff0c;支持自定义sql&#xff0c;存储过程以及高级映射。MyBatis就是可以让我们更加简单的实现程序和数据库之间进行交互的一个工具。可以让我们更加简单的操作和读取数据库的内容。MyBatis的官网&#xff1a;htt…...

R语言基础(五):流程控制语句

R语言基础(一)&#xff1a;注释、变量 R语言基础(二)&#xff1a;常用函数 R语言基础(三)&#xff1a;运算 R语言基础(四)&#xff1a;数据类型 6.流程控制语句 和大多数编程语言一样&#xff0c;R语言支持选择结构和循环结构。 6.1 选择语句 选择语句是当条件满足的时候才执行…...

【Java开发】设计模式 02:工厂模式

1 工厂模式介绍工厂模式&#xff08;Factory Pattern&#xff09;是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式&#xff0c;它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通过使…...

合并两个链表(自定义位置合并与有序合并)LeetCode--OJ题详解

图片: csdn 自定义位置合并 问题&#xff1a; 给两个链表 list1 和 list2 &#xff0c;它们包含的元素分别为 n 个和 m 个。 请你将 list1 中 下标从 a 到 b 的全部节点都删除&#xff0c;并将list2 接在被删除节点 的位置。 比如&#xff1a; 输入&#xff1a;list1 [1…...

Java编程问题总结

Java编程问题总结 整理自 https://github.com/giantray/stackoverflow-java-top-qa 基础语法 将InputStream转换为String apache commons-io String content IOUtils.toString(new FileInputStream(file), StandardCharsets.UTF_8); //String value FileUtils.readFileT…...

binutils工具集——objcopy的用法

以下内容源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 一、工具简介 objcopy主要用来转换目标文件的格式。 在实际开发中&#xff0c;我们会用该工具进行格式转换与内容删除。 &#xff08;1&#xff09;在链接完成后&#xff0c;将elf格式的.out文件转化为bi…...

Windows使用Stable Diffusion时遇到的各种问题和知识点整理(更新中...)

Stable Diffusion安装完成后&#xff0c;在使用过程中会出现卡死、文件不存在等问题&#xff0c;在本文中将把遇到的问题陆续记录下来&#xff0c;有兴趣的朋友可以参考。 如果要了解如何安装sd&#xff0c;则参考本文《Windows安装Stable Diffusion WebUI及问题解决记录》。如…...

MySQL workbench基本查询语句

1.查询所有字段所有记录 SELECT * FROM world.city; select 表示查询&#xff1b;“*” 称为通配符&#xff0c;也称为“标配符”。表示将表中所有的字段都查询出来&#xff1b;from 表示从哪里查询&#xff1b;world.city 表示名为world的数据库中的city表&#xff1b; 上面…...

软件测试详解

文章目录一、软件危机&#xff08;一&#xff09;概念&#xff08;二&#xff09;产生软件危机的原因&#xff08;三&#xff09;消除软件危机的途径二、软件过程模型&#xff08;一&#xff09;软件生命周期概念&#xff08;二&#xff09;软件开发模型1. 瀑布模型2. 螺旋模型…...

YOLOS学习记录

在前面&#xff0c;博主已经完成了YOLOS项目的部署与调试任务&#xff0c;并在博主自己构造的数据集上进行了实验&#xff0c;实验结果表明效果并不显著&#xff0c;其实这一点并不意外&#xff0c;反而是在情理之中。众所周知&#xff0c;Transformer一直以来作为NLP领域的带头…...

数组边遍历(for循环)边删除为什么删不干净 及三种实现删除的方法

文章目录1、为什么删不干净倒序删迭代器lambda表达式删除为什么说数组边for循环遍历边删除会出现删不干净的情况1、为什么删不干净 先写一个例子&#xff1a;可以先猜一下控制台会打印出什么内容&#xff1f; public class removeIterator {public static void main(String[]…...

环境配置之Keepass

前言很久以前&#xff0c;就有了想要一个自己密码管理器的念头。毕竟&#xff0c;即使浏览器能记住各个网站的账号密码&#xff0c;但是在登录单独客户端的时候&#xff0c;仍然要翻找密码。为了省事&#xff0c;也曾经是一个密码走天下。然后被劫持了QQ给同学发黄色小网站&…...