【Linux】进程信号(下)
在上一篇中,我们详细探讨了信号的预备知识和产生方式(如硬件异常、终端输入、kill
命令、系统调用等)及其背后的操作系统行为。信号作为进程间异步通信的核心机制,其生命周期远不止“产生”这一环节——信号的保存与处理才是实现可靠异步事件响应的关键。
一、信号其他相关常见概念
- 实际执行信号的处理动作称为信号递达(Delivery)
- 信号从产生到递达之间的状态,称为信号未决(Pending)。
- 进程可以选择阻塞 (Block )某个信号。
- 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
- 注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
二、信号保存
阻塞信号
在Linux信号机制中,阻塞(Block)与未决(Pending)是信号生命周期中两个关键状态,但其概念常被混淆。通过一个生动的类比,我们可以清晰理解它们的本质区别与联系:
假设你是一名学生,数学老师布置的作业类比为操作系统发送的信号:
- 信号产生:数学老师(进程)布置作业(发送信号),你将其记录在作业本上(未决状态)。
- 未决(Pending):作业已记录,但未开始处理(信号已接收但未被处理)。
- 阻塞(Block):若你因讨厌数学老师,决定暂时不处理他的作业(阻塞信号),但仍会记录所有布置的作业(未决状态),直到你改变态度(解除阻塞)。
- 信号抵达(Deliver):最终你选择完成作业(执行默认处理)、草草应付(忽略)或按自己的方法解题(自定义处理)。
阻塞 vs 忽略:本质区别
- 阻塞(Block)
- 延迟处理:信号被标记为未决,暂不处理,直到解除阻塞。
- 主动控制:即使信号未产生,也可预先设置阻塞(如“无论数学老师是否布置作业,我都拒绝处理”)。
- 忽略(Ignore)
- 处理方式之一:信号抵达时直接丢弃,属于信号处理的三种动作之一(默认、自定义、忽略)。
- 后果:忽略后信号不会被保存,也不会触发后续处理。
Linux信号处理的内核结构
在Linux内核中,信号的产生、保存与处理通过三张核心数据结构实现:未决信号集(Pending)、阻塞信号集(Block)和信号处理函数表(Handler)。这三张表共同管理信号的全生命周期,是理解信号异步处理机制的关键。
Linux通过两个位图管理信号状态:
- 未决信号集(Pending):记录已接收但未处理的信号。
- 操作系统向进程发信号,其实就是向目标进程的判定位图当中进行比特位设置。把比特位直接从0至1就代表的当前我们对应的进程收到了信号。
- 阻塞信号集(Block):定义哪些信号被暂时屏蔽(即使收到信号,也保持未决)。
- 若信号被阻塞,其后续接收的实例会被丢弃(多次SIGINT仅保留一次)。
- SIGKILL(9号)和SIGSTOP(19号)不可被阻塞或忽略,确保管理员始终拥有进程控制权。
信号处理函数表(Handler)
- 本质:函数指针数组,每个元素对应一个信号的处理方式。
- 索引:数组下标为信号编号-1(如SIGINT对应下标1)。
- 处理方式:
- SIG_DFL:默认处理(如终止进程、忽略等)。
- SIG_IGN:忽略信号。
- 自定义函数:用户定义的信号处理函数。
#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";}} }
进程为什么能够识别信号
因为程序员在设计信号这一套体系或者机制的时候,在内核当中已经为每个进程都设置好了。它对应的三种结构分别称为未决信号集(Pending)、阻塞信号集(Block)和信号处理函数表(Handler)。这三个结构组合起来就能够去完成识别信号的一个目的。
阻塞 ≠ 进程阻塞
- 信号阻塞:控制信号的接收与处理流程,属于信号管理机制。
- 进程阻塞:进程因等待资源(如I/O)进入睡眠状态,属于调度范畴。二者毫无关联。
三、信号的捕捉
当一个进程正在运行时,他收到了一个信号。那么该信号在被收到之后,可能并不会被我们立即处理,而是在内核态返回用户态的时候才进行处理该信号。
用户态&&内核态
在谈这两个概念之前,我们先回顾一下用户代码和内核代码。我们所写的代码,诸如数据结构的代码、算法的代码,还有自己所写的所有的代码,在编译运行之后,全部都是运行在用户态的。但是在用户态的时候,我们难免会访问两种资源。第一种叫做操作系统自身的资源,第二个叫做硬件资源。比如说我们现在有一个进程,他想调用getpid(),这个就叫做获取操作系统自身的资源,因为要访问内核数据结构,这些数据是由操作系统去维护的。我们也可能在未来访问我们的硬件资源,诸如调用printf,write,read的方法来读写磁盘,读写文件,或者读写显示器,这都叫做访问硬件资源。无论是操作系统自身的资源,还是硬件资源,它都属于操作系统及其操作系统之下。我们用户在自己写的代码当中,为了访问这些资源,你必须直接或间接的去调用操作系统提供的接口。这批接口我们称之为系统调用。我们在调用系统调用的时候,其实除了你自己调系统调用这件事情。还有一个很重要的事情就是普通用户无法以自己用户态的身份来执行系统调用,必须让自己的状态变成内核态。所以系统调用一定会比普通的你自己写的函数调用成本要高。所以频繁调用系统调用的程序,效率一般都不会特别高,所以我们一般尽量避免叫做频繁调用系统调用。
一个进程,它在实际执行时,他一定要把自己的上下文信息投递到CPU当中。在CPU当中一定会存在着大量的寄存器,而寄存器我们一般可以将寄存器划分为两类。可见寄存器与不可见寄存器。无论是哪一种,其中这些寄存器当中有相当大的一部分都和进程强相关的。在进程当中是有特定用途的,比如会有一些寄存器直接就能够指向当前正在运行的进程的PCB,还有一些寄存器可以保存当前进程的用户级页表。CPU内部还集成了MMU地址转化单元,它根据页表起始地址在CPU内部就完成了虚拟到物理的转化。
虚拟地址到物理地址转化的时候是采用页表这种软件结构和MMU这种硬件结构,软硬件结合的方式。在寄存器中,硬件的速度远远大于软件的速度,因为软件还要从内存和CPU来回迁移。但是硬件一旦电路划分好,它的可维护成本比较高,维护性比较低。软件可以灵活调整更改,软件来维护页表,硬件进行地址转化。进程等于内核数据结构+进程的代码和数据。数据在磁盘中,程序通过exec加载到内存中,操作系统会自动创建虚拟到物理之间的一个映射关系。可执行程序在编译的时候已经按照虚拟地址的方式在编译器内部给我们编译好了。加载好之后,操作系统会帮助我们创建对应的内核数据结构。
CR3寄存器里面有对应的比特位用来表征当前进程的状态,表征了当前进程的运行级别。对应的数字如果为零,表示内核态,如果为三,表示用户态。
凡是和当前进程强相关的,我们也就是说这个寄存器上直接保存或间接保存的是这个进程的相关数据。我们都称之为当前进程的上下文数据。当进程在切换的时候,它除了切换PCB地址空间页表这些东西,它其中还要帮我们去切换进程的是CPU内的匹配它对应的上下文。寄存器只有一套,但寄存器里面的值可以有多套。每个进程在切走的时候,可以把自己的上下文带走,当进程回来的时候再把自己的上下文拿回来。
- 用户态(毕业生身份)
- 权限限制:如同小学毕业生只能访问教室等基础区域
- 操作限制:无法直接操作硬件或访问核心系统资源(类似无法进入校长办公室)
- 内核态(教师/校长身份)
- 特权模式:拥有系统完全控制权(可访问所有区域)
- 关键能力:直接操作硬件、管理内存、调度进程(类似审批教学计划)
- 典型场景:执行系统调用、处理中断、驱动硬件
再次理解地址空间
我们今天介绍一下地址空间里面的内核空间。内核空间的映射的就是让当前进程去映射到操作系统的。每个进程都有自己的代码和数据,一定被放在物理内存的不同区域。为了进程保证独立性,每个进程都有自己独立的用户级页表。其实还在操作系统内部,它还维护了一张内核级页表。内核级页表是操作系统为了维护从虚拟到物理之间的操作系统级别的代码所构建的一张内核映射表。在开机的时候,是要把操作系统加载到内存的,因为操作系统只有一份,所以它的代码和数据在系统内就是唯一的,所以内核级页表只需要一份就足够了。所以每个进程都可以用内核级页表的方式去访问访问操作系统的代码和数据。访问操作系统的接口其实只需要在自己的地址空间上进行跳转即可。操作系统本身要做好一些权限管理,很多东西不允许你访问,最多只让你访问系统调用接口。
当我们的进程它在执行我们对应的想跳转到这个区域的时候,那么它必须得保证自己要更改一下我们当前进程所对应的运行级别,CPU内对应的就是CR3寄存器。实际上系统调用接口,它在最开始的时候,还是在用户态执行的,然后在系统调用的开头通过Int 80陷入内核的方式使得用户态转为内核态,在系统调用结尾再转换到用户态,会把你的用户权限从我们对应的叫做三号状态改成零号状态,然后才让你跳转到这个区域去访问操作系统的代码和数据。
无论是内核态还是用户态,一定是当前这个进程正在运行。无非就是我当前的执行级别是用户态还是内核态的。然后用的页表是用户级页表还是内核级页表,访问的资源是操作系统的还是我自己的,其中我们在状态变化的时候,意味着我们要做一大堆的资源切换。诸如我们要修改我们的状态寄存器,陷入内核进行函数跳转等等。这些都比较费时间, (我们好不容易切换成内核态了,为了提升效率,操作系统要多做一些事情)所以从内核态返回用户态时,他要做信号捕捉处理。那什么时候我会进入内核态呢?最典型的就是系统调用。第二个叫做进程切换。还有包括异常、缺陷、陷阱等等。一个进程在切换时,他没有被执行完,一定被放到运行队列或者等待队列。放过去的时候,他就一定要处于内核态,以操作系统的身份把我才能放过去。
能不能以内核态的身份执行用户态代码?
从技术上可以。但是从设计方面一定不可以,因为操作系统不信任任何人提供的接口。操作系统它无法直接去识别到你的逻辑究竟是非法还是合法。所以操作系统虽然他觉得他自己能,但是不敢。如果直接以内核态的身份去执行用户的代码很容易,这份代码如果被恶意分子利用,就可以以一个内核态的身份去进行一定程度的越权,进行一系列的非法动作。所以当我们在进行我们对应的捕捉,处理这个信号的时候,绝对不能以内核态的身份去执行,他要重新将身份更改为用户态。
信号捕捉全过程
简略图如下:因为横线和无穷大有四个交点,所以它一定在信号处理过程之中,如果是自定义动作,一定是需要四次状态切换。
相关系统调用函数
sigset_t
每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。
因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。因为只有一个位图,所以只能改一次。你发很多次,他也是相当于只能捕捉一次
信号集操作函数
#include <signal.h>
int sigemptyset(sigset_t *set);// 初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号。
int sigfillset(sigset_t *set); //初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。
int sigaddset (sigset_t *set, int signo);//新增
int sigdelset(sigset_t *set, int signo);//清除
int sigismember(const sigset_t *set, int signo);//用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1
- 注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>// volatile: 保持内存可见性!
// volatile int quit = 0;void handler(int signo)
{// 1. 我有非常多的子进程,在同一个时刻退出了// waitpid(-1) -> while(1)// 2. 我有非常多的子进程,在同一个时刻只有一部分退出了// while(1)// {// pid_t ret = waitpid(-1, NULL, WNOHANG);// if(ret == 0) break;// }// printf("pid: %d, %d 号信号,正在被捕捉!\n", getpid(), signo);// printf("quit: %d", quit);// quit = 1;// printf("-> %d\n", quit);
}void Count(int cnt)
{while (cnt){printf("cnt: %2d\r", cnt);fflush(stdout);cnt--;sleep(1);}printf("\n");
}int main()
{// 显示的设置对SIGCHLD进行忽略signal(SIGCHLD, SIG_IGN);signal(SIGCHLD, SIG_DFL);printf("我是父进程, %d, ppid: %d\n", getpid(), getppid());pid_t id = fork();if (id == 0){printf("我是子进程, %d, ppid: %d,我要退出啦\n", getpid(), getppid());Count(5);exit(1);}while (1)sleep(1);// signal(2, handler);// while(!quit);// printf("注意, 我是正常退出的!\n");return 0;
}// #include <iostream>
// #include <cstdio>
// #include <signal.h>
// #include <unistd.h>// using namespace std;// void Count(int cnt)
// {
// while(cnt)
// {
// printf("cnt: %2d\r", cnt);
// fflush(stdout);
// cnt--;
// sleep(1);
// }
// printf("\n");
// }// void handler(int signo)
// {
// cout << "get a signo: " << signo << "正在处理中..." << endl;
// Count(20);
// }// int main()
// {
// struct sigaction act, oact;
// act.sa_handler = handler;
// act.sa_flags = 0;
// sigemptyset(&act.sa_mask); // 当我们正在处理某一种信号的时候,我们也想顺便屏蔽其他信号,就可以添加到这个sa_mask中
// sigaddset(&act.sa_mask, 3);
// sigaction(SIGINT, &act, &oact);// while(true) sleep(1);// return 0;
// }
当某个信号的处理函数被调用时,操作系统会自动将当前信号加入到进程的信号屏蔽字(block)里面。然后当信号处理函数返回时,自动恢复为原来的信号屏蔽值。这样的话就保证当我们在一个时间段内大量的信号同样的信号产生时,我们并不会因为这个信号被重复高频次的调用而产生函数出现问题。比如说递归了或者是重复进入了这样的情况。那么同类型的信号捕捉方法,它一定是要串行执行的,这也减少了系统设计的一个难度或者成本。
四、volatile关键字
我们站在信号的角度理解一下这个关键字
#include <stdio.h>
#include <signal.h>
int flag = 0;
void handler(int sig)
{printf("chage flag 0 to 1\n");flag = 1;
}
int main()
{signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}
标准情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 , while 条件不满足,退出循环,进程退出。优化情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 ,但是 while 条件依旧满足,进程继续运行!但是很明显flag肯定已经被修改了,但是为何循环依旧执行?很明显, while 循环检查的flag,并不是内存中最新的flag,这就存在了数据二异性的问题。 while 检测的flag其实已经因为优化,被放在了CPU寄存器当中。如何解决呢?很明显需要 volatile。
volatile 作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作
结语
以上就是我对 【Linux】进程信号(下)
的理解,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉
相关文章:
【Linux】进程信号(下)
在上一篇中,我们详细探讨了信号的预备知识和产生方式(如硬件异常、终端输入、kill命令、系统调用等)及其背后的操作系统行为。信号作为进程间异步通信的核心机制,其生命周期远不止“产生”这一环节——信号的保存与处理才是实现可…...
华为数字芯片机考2025合集2已校正
单选 1. 题目内容 关于亚稳态的描述错误的是( )。 1. 解题步骤 1.1 理解亚稳态(Metastability)的核心特性 亚稳态是指触发器无法在指定时间内稳定输出有效逻辑电平(0或1)的状态,其关键特点…...
【大模型微调】如何解决llamaFactory微调效果与vllm部署效果不一致如何解决
以下个人没整理太全 一、生成式语言模型的对话模板介绍 使用Qwen/Qwen1.5-0.5B-Chat训练 对话模板不一样。回答的内容就会不一样。 我们可以看到例如qwen模型的tokenizer_config.json文件,就可以看到对话模板,一般同系列的模型,模板基本都…...
基于视觉语言模型的机器人实时探索系统!ClipRover:移动机器人零样本视觉语言探索和目标发现
作者:Yuxuan Zhang 1 ^{1} 1, Adnan Abdullah 2 ^{2} 2, Sanjeev J. Koppal 3 ^{3} 3, and Md Jahidul Islam 4 ^{4} 4单位: 2 , 4 ^{2,4} 2,4佛罗里达大学电气与计算机工程系RoboPI实验室, 1 , 3 ^{1,3} 1,3佛罗里达大学电气与计算机工程系F…...
Java常用工具算法-6--秘钥托管云服务AWS KMS
前言: 之前我们介绍了一些常用的加密算法(如:对称加密AES,非对称加密RSA,ECC等),不论是哪一种都需要涉及到秘钥的管理。通常的做法都是把秘钥放到配置文件中进行配置,但是对于一些高…...
Shell脚本的学习
编写脚本文件 定义以开头:#!/bin/bash #!用来声明脚本由什么shell解释,否则使用默认shel 第一步:编写脚本文件 #!/bin/bash #注释 echo "这是输出" 第二步:加上执行权限:chmod x 脚本文件名.sh 第三步&…...
Java——pdf增加水印
文章目录 前言方式一 itextpdf项目依赖引入编写PDF添加水印工具类测试效果展示 方式二 pdfbox依赖引入编写实现类效果展示 扩展1、将inputstream流信息添加水印并导出zip2、部署出现找不到指定字体文件 资料参考 前言 近期为了知识库文件导出,文件数据安全处理&…...
Redis过期key处理、内存淘汰策略与缓存一致性策略实践方案
在现代的高性能应用开发中,Redis作为一款极为热门的内存数据库,其快速的读写性能和丰富的数据结构使其在缓存、消息队列等诸多领域得到了广泛应用。然而,在实际使用过程中,处理好Redis过期key、选择合适的内存淘汰策略以及确保缓存…...
深入 C++ 线程库:从创建到同步的探索之旅
C在<thread>中定义了C线程库. 创建多线程 #include <iostream> #include <thread> using namespace std; void show(int id, int count) { //线程函数for (int i 0; i < count; i) {cout << "id:" << id << ",值:&qu…...
LangChain使用大语言模型构建强大的应用程序
LangChain简介 LangChain是一个强大的框架,旨在帮助开发人员使用语言模型构建端到端的应用程序。它提供了一套工具、组件和接口,可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互ÿ…...
程序化广告行业(72/89):Tag Manager系统代码操作与行业发展剖析
程序化广告行业(72/89):Tag Manager系统代码操作与行业发展剖析 大家好!在技术领域不断探索的过程中,我深刻体会到知识共享的重要性。写这篇博客,就是希望能和大家一起深入了解程序化广告行业,…...
数据结构实验3.3:求解迷宫路径问题
文章目录 一,问题描述二,基本要求三,算法分析(一)整体思路(二)详细步骤1. 输入迷宫大小并生成迷宫2. 定义走步规则3. 深度优先搜索(DFS)4. 输出结果 (三&…...
基于SpringBoot的线上历史馆藏系统【附源码】
基于SpringBoot的线上历史馆藏系统(源码L文说明文档) 4 系统设计 系统在设计的过程中,必然要遵循一定的原则才可以,胡乱设计是不可取的。首先用户在使用过程中,能够直观感受到功能操作的便利性,符合…...
Mybatis的springboot项目使用
删除数据 & 占位符 一般常用占位符进行数据库操作,也就是预编译sql。 在UserMapper中定义删除接口 /** 根据id删除用户*/ Delete("delete from user where id #{id}") void deleteById(Integer id);若想要获取返回值,声明为Integer (s…...
网站集群批量管理-Ansible剧本与变量
复盘内容:链接指北 查看ansible命令文档 ansible-doc -s systemd一、剧本 何为剧本: playbook 文件,用于长久保存并且实现批量管理,维护,部署的文件. 类似于脚本存放命令和变量 剧本yaml格式,yaml格式的文件:空格,冒号. 剧本未来我们批量管理,运维必会的内容. …...
HOW - React Developer Tools 调试器
目录 React Developer Tools使用Components 功能特性1. 查看和编辑 props/state/hooks2. 查找组件3. 检查组件树4. 打印组件信息5. 检查子组件 Profiler 功能特性Commit ChartFlame Chart 火焰图Ranked Chart 排名图 why-did-you-render 参考文档: React调试利器&a…...
Spring Cloud Alibaba微服务治理实战:Nacos+Sentinel深度解析
一、引言 在微服务架构中,服务发现、配置管理、流量控制是保障系统稳定性的核心问题。Spring Cloud Netflix 生态曾主导微服务解决方案,但其部分组件(如 Eureka、Hystrix)已进入维护模式。 Spring Cloud Alibaba 凭借 高性能、轻…...
《AI换脸时代的攻防暗战:从技术滥用走向可信未来》
技术迭代图谱 过去五年里,Deepfake技术经历了飞速迭代,从最初的萌芽到如今的广泛应用和对抗措施形成。2017年前后,利用深度学习进行人脸换装的技术首次在社区中出现。一位Reddit网友昵称“deepfakes”,将名人面孔替换到色情影片上…...
25/4/9 算法笔记 DBGAN+强化学习+迁移学习实现青光眼图像去模糊1
整体实验介绍 实验主要是结合DBGAN对抗网络强化学习增强迁移学习增强实现青光眼图像去模糊。今天则是先完成了DBGAN板块模型的训练。 实验背景介绍 青光眼的主要特征有: 视盘形态与杯盘比CDR:青光眼患者主要表现为视杯扩大,盘沿变窄。 视…...
【Claude AI大语言模型连接Blender生成资产】Windows安装Blender MCP教程
前言 最近在学习资产制作,了解到了个好玩的东西,利用AI一步一步搭建资产: 上面这副图就是利用Claude AI调用Blender的Python接口一步一步实现的,挺丑但好玩。 安装教程 进入Github: Blender-MCP 网站,下载该项目&a…...
JSP运行环境安装及常用HTML标记使用
制作一个静态网站的基本页面index.html 实验代码:<form> <label for"username">用户名:</label> <input type"text" id"username" name"username"><br> <label for"password&…...
Git 的进阶功能和技巧
1、分支的概念和使用 1.1、什么是分支? 分支(Branch)是在版本控制中非常重要的概念。几乎所有版本控制系统都支持某种形式的分支。在 Git 中,分支是 Git 强大功能之一,它允许我们从主开发线分离出来,在不…...
WSL1升级到WSL2注意事项
今天要在WSL上安装docker,因为机器上安装了wsl1,docker安装后启动不了,通过询问deepseek发现docker只能在wsl2上安装,因此就想着将本机的wsl1升级到wsl2。 确保你的 Windows 系统是 Windows 10(版本 1903 及以上&…...
392. 判断子序列
https://leetcode.cn/problems/is-subsequence/?envTypestudy-plan-v2&envIdtop-interview-150因为是子序列我们只要关心后一个字符在前一个字符后面出现过就行,至于在哪出现出现几次我们不关心,所以我们可以用HashMap<Character, ArrayList<…...
在 VMware 中为 Ubuntu 24.04 虚拟机设置共享文件夹后,在虚拟机中未能看到共享的内容
在 VMware 中为 Ubuntu 24.04 虚拟机设置共享文件夹后,如果在虚拟机中未能看到共享的内容,可能是由于以下原因: VMware Tools 未正确安装:共享文件夹功能依赖于 VMware Tools 或 Open VM Tools。如果未安装或安装不完整࿰…...
台式电脑插入耳机没有声音或麦克风不管用
目录 一、如何确定插孔对应功能1.常见音频插孔颜色及功能2.如何确认电脑插孔?3.常见问题二、 解决方案1. 检查耳机连接和设备选择2. 检查音量设置和静音状态3. 更新或重新安装声卡驱动4. 检查默认音频格式5. 禁用音频增强功能6. 排查硬件问题7. 检查系统服务8. BIOS设置(可选…...
Windchill开发-WTContainer相关API整理
Windchill开发-WTContainer相关API整理 概述各容器对象相关方法站点容器组织容器产品容器/存储库容器上下文团队角色组 文件夹 方法汇总 概述 Windchill 的环境由一组容器组成,容器分为三级:第一级为站点容器,第二级为组织容器,第…...
理解JSON-RPC 2.0 协议
JSON-RPC 2.0是指一种基于 JSON 的远程过程调用协议,用于在网络上进行跨平台和跨语言的通信。它提供了一种简单、轻量级的方式来实现客户端和服务器之间的方法调用和数据交换。在原文中,JSON-RPC 2.0被用来描述 STDIO 传输机制中消息的格式,即…...
【 C# 使用 MiniExcel 库的典型场景】
以下是 C# 使用 MiniExcel 库的典型场景及代码示例: 一、基础读取操作 强类型读取(需定义数据模型类) 定义与 Excel 列名匹配的类后直接映射为对象集合: csharp Copy Code public class UserAccount { public int Id { get; …...
创建 Pod 失败,运行时报错 no space left on device?
遇到创建Pod失败并报错“no space left on device”时,请按照以下步骤排查和解决问题: 1. 定位问题来源 查看Pod事件: kubectl describe pod <pod-name> -n <namespace> 在输出中查找 Events 部分,确认错误是否与…...
[leetcode]查询区间内的所有素数
一.暴力求解 #include<iostream> #include<vector> using namespace std; vector<int> result; bool isPrime(int i) { if (i < 2) return false; for (int j 2;j * j < i;j) { if (i % j 0) { …...
【Web安全】如何在 CDN 干扰下精准检测 SSRF?Nuclei + Interactsh 实战
❤️博客主页: iknow181 🔥系列专栏: 网络安全、 Python、JavaSE、JavaWeb、CCNP 🎉欢迎大家点赞👍收藏⭐评论✍ 背景 在日常漏洞复核中,我们常用 DNSLog 平台判断目标是否存在 SSRF 漏洞:只要请…...
输入框只能输入非中文字符
在 Qt 中,可以通过设置输入法过滤器(QInputContext)或使用正则表达式来限制输入框(QLineEdit 或 QTextEdit)只能输入非中文字符。以下是两种实现方法: ### 方法 1:使用正则表达式 可以通过 QLi…...
LeeCode 136. 只出现一次的数字
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。 示例 1 : 输入࿱…...
Traefik应用:配置容器多个网络时无法访问问题
Traefik应用:配置容器多个网络时无法访问问题 介绍解决方法问题原因: **容器多网络归属导致 Traefik 无法正确发现路由规则**。解决方案方法 1:将应用容器 **仅连接** 到 traefik-public 网络方法 2:显式指定 Traefik 监听的网络 …...
超便捷超实用的文档处理工具,PDF排序,功能强大,应用广泛,无需下载,在线使用,简单易用快捷!
小白工具https://www.xiaobaitool.net/files/pdf-sort/ 中的 PDF 排序功能是一项便捷实用的文档处理服务,以下是其具体介绍: 操作便捷直观:用户上传 PDF 文件后,可通过直接拖动页面缩略图来调整顺序,就像在纸质文档中…...
zsh: command not found - 鸿蒙 HarmonyOS Next
终端中执行 hdc 命令抛出如下错误; zsh: command not found 解决办法 首先,查找到 DevEco-Studio 的 toolchains 目录路径; 其次,按照类似如下的文件夹层级结果推理到 toolchains 子级路径下,其中 sdk 后一级的路径可能会存在差异,以实际本地路径结构为主,直至找到 openharm…...
【动态规划】 深入动态规划—两个数组的dp问题
文章目录 前言例题一、最长公共子序列二、不相交的线三、不同的子序列四、通配符匹配五、交错字符串六、两个字符串的最小ASCII删除和七、最长重复子数组 结语 前言 问题本质 它主要围绕着给定的两个数组展开,旨在通过对这两个数组元素间关系的分析,找出…...
金融数据分析(Python)个人学习笔记(7):网络数据采集以及FNN分类
一、网络数据采集 证券宝是一个免费、开源的证券数据平台(无需注册),提供大盘准确、完整的证券历史行情数据、上市公司财务数据等,通过python API获取证券数据信息。 1. 安装并导入第三方依赖库 baostock 在命令提示符中运行&…...
指定运行级别
linux系统下有7种运行级别,我们需要来了解一下常用的运行级别,方便我们熟悉以后的部署环境,话不多说,来看. 开机流程: 指定数级别 基本介绍 运行级别说明: 0:关机 相当于shutdown -h now ⭐️默认参数不能设置为0,否则系统无法正常启动 1:单用户(用于找回丢…...
7.第二阶段x64游戏实战-string类
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:7.第二阶段x64游戏实战-分析人物属性 string类是字符串类,在计算机中…...
【MySQL基础】左右连接实战:掌握数据关联的完整视图
1 左右连接基础概念 左连接(left join)和右连接(right join)是MySQL中两种重要的表连接方式,它们与内连接不同,能够保留不匹配的记录,为我们提供更完整的数据视图。 核心区别: left join:保留左表所有记录,…...
建筑工程行业如何选OA系统?4大主流产品分析
工程行业项目的复杂性与业务流程的繁琐性对办公效率提出了极高要求。而OA 系统(办公自动化系统)的出现,为工程企业提供了一种全新的、高效的管理模式。 工程行业OA系统选型关键指标 功能深度:项目管理模块完整度、文档版本控制能…...
动态科技感html导航网站源码
源码介绍 动态科技感html导航网站源码,这个设计完美呈现了科幻电影中的未来科技界面效果,适合展示技术类项目或作为个人作品集的入口页面,自适应手机。 修改卡片中的链接指向你实际的HTML文件可以根据需要调整卡片内容、图标和颜色要添加更…...
CLIPGaze: Zero-Shot Goal-Directed ScanpathPrediction Using CLIP
摘要 目标导向的扫描路径预测旨在预测人们在搜索视觉场景中的目标时的视线移动路径。大多数现有的目标导向扫描路径预测方法在面对训练过程中未出现的目标类别时,泛化能力较差。此外,它们通常采用不同的预训练模型分别提取目标提示和图像的特征,导致两者之间存在较大的特征…...
wsl-docker环境下启动ES报错vm.max_map_count [65530] is too low
问题描述 在windows环境下用Docker Desktop(wsl docker)启动 elasticsearch时报错 max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]解决方案 方案一 默认的vm.max_map_count值是65530,而es需要至少262…...
js chrome 插件,下载微博视频
起因, 目的: 最初是想下载微博上的NBA视频,因为在看网页上看视频很不方便,快进一次是10秒,而本地 VLC 播放器,快进一次是5秒。另外我还想做点视频剪辑。 对比 原来手动下载的话,右键检查,复制…...
游戏引擎学习第212天
"我们将同步…"α 之前我们有一些内容是暂时搁置的,因为在调整代码的过程中,我们做了一些变动以使代码更加简洁,这样可以把数据放入调试缓冲区并显示出来,这一切现在看起来已经好多了。尽管现在看起来更好,…...
PXE远程安装服务器
目录 搭建PXE远程安装服务器 1、准备Linux安装源: 2、安装并启用TFTP服务: 3、准备Linux内核、初始化镜像文件 4、准备PXE引导程序 5、安装并启用DHCP服务 6、(1)配置启动菜单文件(有人应答) 6、(2)…...
软件测试之功能测试详解
一、测试项目启动与研读需求文档 (一) 组建测试团队 1、测试团队中的角色 2、测试团队的基本责任 尽早地发现软件程序、系统或产品中所有的问题。 督促和协助开发人员尽快地解决程序中的缺陷。 帮助项目管理人员制定合理的开发和测试计划。 对缺陷进行…...