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

Linux 操作系统 --- 信号

序言

 在本篇内容中,将为大家介绍在操作系统中的一个重要的机制 — 信号。大家可能感到疑惑,好像我在使用 Linux 的过程中并没有接触过信号,这是啥呀?其实我们经常遇到过,当我们运行的进程当进程尝试访问非法内存地址时,我们的进程会被中断,这是因为操作系统向该进程发送了中断信号。
Linux 操作系统离不开信号机制,在这篇文章中,让我们走进信号,了解信号的从哪里来,又到哪里去。


1. 信号的概念

1.1 定义

 信号是操作系统向进程发送的一种通知,表示某个特定事件已经发生。在Unix、类Unix 以及其他系统中,信号被广泛使用。

1.2 特点

 信号具有如下的特点:

  • 异步性:信号的产生对进程来说是异步的,即 进程无法预知信号何时到来
  • 通知机制:信号是一种 软件中断(由软件程序触发的中断方式),用于中断进程的正常执行流程,使其处理特定事件。
  • 进程间通信:虽然信号主要用于异常处理和系统调试,但也可以用于进程间的基本通信。

1.3 种类

 在 Linux 系统下,使用指令:kill -l 即可查看所有的信号:
在这里插入图片描述

信号是使用宏定义的,每个信号前面的数字,就是该信号宏对应的值。

前 31 个信号为常规信号,其余为实时信号。在本篇文章中,我们主要讨论前 31 个常规信号。

 你也可以使用指令: man 7 signal 查看每一个详细信息:
在这里插入图片描述

补充知识点:Core && Term

 在描述信号的字段中,有一个叫做 Action 的特征,他的值大多都是 Core Term 这是什么呢?

Term

termterminate 的缩写,表示默认动作是终止进程。当进程接收到一个默认动作为 term 的信号时,进程会被立即终止。

Core

core 表示 默认动作是终止进程并生成一个核心转储(core dump)文件。核心转储是一个包含进程在终止时的内存映像的文件,它对于调试程序非常有用,因为它 提供了进程终止时的状态信息
 咦?就比如,SIGSEGV 段错误 当我的程序非法访问被终结时,被没有产生传说中的核心转储文件呀?这是因为你的服务器默认关闭了该功能,使用指令 ulimit -a 查看:
在这里插入图片描述
现在我们使用指令 ulimit -c 4096 开启该功能:
在这里插入图片描述

现在我们运行下一段程序:

   8 int main()9 {10 11     int *ptr = NULL;12     *ptr = 1;13     14     return 0;15 }

程序不负众望地报错并退出了,产生了一个文件:
在这里插入图片描述
这个文件可以干嘛呢?当我们的程序出现异常时,相当该文件保存了案发现场,具体的用法是:

  • 首先使用 gdb 调试你的程序:
    在这里插入图片描述
  • 之后输入指令 core-file your_core
    在这里插入图片描述

可以看到,直接就复原了事故现场。

区别
  • 进程终止:term 信号会终止进程,但 不生成核心转储文件term 信号通常是用于请求进程正常终止的情况。
  • 调试信息:core 信号不仅会终止进程,还会 生成核心转储文件,这包含了进程的内存映像、寄存器状态、堆栈跟踪等信息,用于调试目的。

2. 信号的产生

 信号是从哪里产生的呢?虽然最后都是操作系统来执行对一个进程发送信号,但是是谁告诉操作系统这样做的呢?

2.1 用户操作 — kill 指令

 当我们运行一个程序时,可以通过指令 kill 来让操作系统对该进程发送相应的信号,就比如,我们可以手动发送 SIGKILL 9号 信号将该进程终结,这里有一个程序:

 1 TestSig1.cc                                                                                                                                                                                                  X 1 #include <iostream>2 #include <unistd.h>3 4 5 int main()6 {7     while(true)8     {9         std::cout << "I am Running, my pid is " << getpid() << std::endl;10         sleep(1);11     }12     return 0;13 }

该程序会每秒打印相应的内容,现在我们可以使用相关的指令 kill -9 [pid] 来杀掉该进程:
在这里插入图片描述
可以看到该进程被杀掉了!!!

2.2 用户操作 — 按键操作

 我们也可通过按键来让操作系统发送相关的信号,就比如我们平时终止一个进程的方式更多的是通过键盘按键,就比如 ctrl + c
在这里插入图片描述
其实这个按键对应的就是 3 号信号 SIGQUIT

2.3 用户操作 — 系统调用

 操作系统提供一个系统调用 int kill(pid_t pid, int sig); 该函数你可以想指定进程发送信号:

  • pid: 表示要发送信号的进程 ID
  • sig: 表示要发送的信号
  • 返回值:成功返回 0 ,失败返回 -1 ,错误码被设置

还有一个函数是 int raise(int sig);,该函数是向当前进程发送指定信号,简单来说,相当于简化的 kill => kill(getpid(), int sig);

2.4 触发软件条件

 在之前管道的学习中,我们了解到如果 读端被关闭了,写端一直再写,那么操作系统就会认为这是一个坏掉的管道,就会发送 13 号信号 SIGPIPE 终止该进程,这就是触发了某种软件条件。
 现在,在这里先向大家介绍几个非常重要的函数:

signal 函数

 该函数允许程序员定义当特定信号发生时,程序应该如何响应, 简单说,这个函数用于捕获特定信号,然后执行指定操作的sighandler_t signal(int signum, sighandler_t handler);:

  • signum:指定要处理的信号类型。注意,SIGKILLSIGSTOP 这两个信号不能被捕获、阻塞或忽略。
  • handler:指定信号的处理方式。它可以是一个函数指针,指向一个用户定义的信号处理函数;也可以是 SIG_IGN,表示忽略该信号;或者是 SIG_DFL,表示采用信号的默认处理方式。
  • 返回值:成功时,signal 函数返回之前为该信号设置的信号处理函数的指针。如果之前没有为该信号设置过处理函数,则返回 SIG_DFL。失败时,返回 SIG_ERR,并设置 errno 以指示错误原因。

看着描述这么多,其实用起来不复杂,比如,现在我要捕获 2 号信号 SIGINT,他的默认操作是退出,现在我不想要推出,想要执行我的逻辑:

 1 TestSig1.cc                                                                                       X 1 #include <iostream>2 3 #include <unistd.h>4 #include <sys/types.h>5 #include <signal.h>6 7 void signal_handle(int signum)8 {9     std::cout << "I got you signal: " << signum << std::endl;10 }11 12 int main()13 {14 15     // 2号信号的捕获16     signal(2, signal_handle);17 18     while(true)19     {20         std::cout << "I am Running, my pid is " << getpid() << std::endl;21         sleep(1);22     }23     return 0;24 }

现在我们使用 ctrl + c 已经不能终止该进程了:
在这里插入图片描述

你也可将 signal(2, signal_handle); 中的函数换成 SIG_IGN 这样就会忽略该信号。

现在我有个想法就是将全部信号都捕获,在写个死循环,是不是就没有人把我停下来了!!!我们能想到的,人家肯定也想到了,规定 9 号信号 SIGKILL 和 19 号信号 SIGSTOP 这两个信号不能被捕获、阻塞或忽略。保证系统的稳定性和管理员的控制权。

alarm 函数

 大家为了早起都设置过闹钟吧,闹钟的作用就是时间一到就提醒我们执行某件任务。在 Linux 中的闹钟 alarm 也是一样的,我们设置一个定时,当时间一到执行某项任务,unsigned int alarm(unsigned int seconds);

  • seconds:定时器应该等待的秒数。如果 seconds 是 0,则任何当前设置的定时器都会被取消(你可以同时设置多个闹钟),但不会发送 SIGALRM 信号。
  • 返回值:如果之前已经设置了定时器,alarm 函数 返回之前设置的剩余时间(秒),直到定时器到期。如果之前没有设置定时器,则返回 0。

alarm 定时器到期时,会向进程发送 SIGALRM 信号,终止进程:

12 int main()13 {14 15     // 设置一个闹钟,执行默认操作16     alarm(2);17 18     while(true)19     {20         std::cout << "I am Running, my pid is " << getpid() << std::endl;21         sleep(1);22     }23     return 0;24 }

两秒之后,进程自动终止:

 但更多情况下,我们想要闹钟解释后执行我们的逻辑,而不是终止进程,那咋办呢? 捕获该信号,自定义处理信号,这就需要我们上面说的 signal 函数了:

   7 void signal_handle(int signum)8 {9     std::cout << "Your alarm clock is ringing." << std::endl;10 }11 12 int main()13 {14 15     // 设置一个闹钟,执行默认操作16     alarm(2);17     // 捕获闹钟信号18     signal(SIGALRM, signal_handle);19 20     while(true)21     {22         std::cout << "I am Running, my pid is " << getpid() << std::endl;23         sleep(1);24     }25     return 0;26 }

现在闹钟时间到了,就不会终止进程啦!但是,我还有一个疑问,你这个闹钟只能执行一次呀,之后就失效了,我想要一个一直生效的定时任务,怎么做到呢?当捕获并执行自定义函数时再设置一个闹钟不就好啦:

   7 void signal_handle(int signum)8 {9     std::cout << "Your alarm clock is ringing." << std::endl;10     alarm(2);11 }

这样就得到一个持续的定时任务啦:
在这里插入图片描述

 在这里的闹钟就是一个触发了软件条件(倒计时),从而产生信号发送给进程!

2.4 硬件异常

段错误

 在我们的程序中,很可能涉及到 段错误(非法内存访问),具体触发错误的细节如下:

  • 现代计算机使用内存管理单元(MMU)来管理内存。MMU 负责 将虚拟地址(程序使用的地址)映射到物理地址(实际内存地址)
  • 当我们尝试访问一个地址时,MMU 尝试将虚拟地址翻译为物理地址,并检查该虚拟地址对应的页表项,以确定是否有权限访问该地址,以及地址是否有效
  • CPU 发现该块地址是 无效的,或者是不具有写权限的,或者是无权限访问的,将触发异常
  • 操作系统向该进程发送 SIGSEG 的信号

这就是简单的硬件异常触发流程。


3. 信号的保存

 现在我们已经基本了解了信号是从哪里来的,那么信号被一个进程接受过后,是以什么形式存在于进程当中呢?

 在介绍信号的保存之前,希望大家记住这几个概念:

  • 实际执行信号的处理动作称为信号递达(Delivery)
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。

 信号的信息被保存在一个进程的 task_struct 中:
在这里插入图片描述
我们来好好的介绍这 3 个结构:

3.1 block 位图

Block 位图用于指示哪些信号当前被进程 阻塞。如果一个信号在 Block 位图中对应的位被设置(为 1 ),那么即使该信号已经到达,它也不会被立即处理,而是会 保持在未决状态,直到进程解除对该信号的阻塞。

3.2 pending 位图

Pending 位图(通常不是直接暴露给用户的,而是作为进程控制块 task_struct 的一部分)用于 跟踪哪些信号已经到达进程但尚未被处理。每个位代表一个信号,如果该位被设置(通常为 1 ),则表示对应的信号已经到达且处于 未决状态

3.3 handler 函数指针数组

 用户可以通过系统调用来设置特定信号的处理函数。当用户为某个信号注册了一个自定义的处理函数时,操作系统就会将该函数的地址存储在 handler 表中对应信号编号的位置。如果用户没有为某个信号设置自定义处理函数,那么当该信号发生时,操作系统就会 调用默认的处理函数

 所以,我们总结一下,当一个信号传递给进程时,操作系统会将 pending 表中该信号对应的值置 1,如果 block表中的对应的值 也是 1,代表该信号被阻塞,不会被立即处理,直至解除阻塞;当解除阻塞或者一开始就不是阻塞状态的话,就会执行 handle
表中该信号对应的函数操作。

3.4 验证结论

 现在我们准备验证我们的想法,我们先阻塞一个信号,然后发送该信号,查看是否执行相关操作,在解除对该信号的阻塞,再次观察现象:

在这里会涉及到对信号集的操作,大家可以简单理解为 对信号集进行的对某个信号的阻塞操作最终会保存到阻塞表中 ,在这里就不具体说明操作了,感兴趣的小伙伴,我找了一篇比较好的文章 👉信号集操作指南。

6 // 自定义函数7 void signal_handler(int signum)8 {9     std::cout << "Recived signal SIGINT!!!" << std::endl;10 }11 12 int main()13 {14     // 捕获信号15     signal(SIGINT, signal_handler);16 17     sigset_t sigset;18     // 初始化信号集19     sigemptyset(&sigset);20     // 添加指定信号到信号集21     sigaddset(&sigset, SIGINT);22 23     // 阻塞该信号24     if(sigprocmask(SIG_BLOCK, &sigset, NULL) == -1)25     {26         perror("sigprocmask");27     }28 29     std::cout << "SIGINT is blocked. Try pressing Ctrl+C after 5s!!!\n" << std::endl;30     sleep(5);31 32     // 解除阻塞33     if(sigprocmask(SIG_UNBLOCK, &sigset, NULL) == -1)34     {35         perror("sigprocmask");36     }37 38     std::cout << "SIGINT is unblocked. Try pressing Ctrl+C!!!\n" << std::endl;39 40     while(true)41     {42         sleep(1);43     }44 }

在这里插入图片描述

第一次我们按 ctrl + c 没什么反应,过了 5s 后,函数自动被执行,可以看出我们的结论是正确的。


4. 信号的处理

 现在我们知道信号哪里来的了,也知道保存在哪里了,现在我们来看看信号的处理方式。

4.1 执行默认方式

 对于没有为其注册信号处理函数的信号,进程会执行该信号的默认操作。就比如,SIGTERM 信号的默认操作是请求进程终止,而 SIGSEGV(段错误)信号的默认操作是生成core文件并终止进程。

4.2 调用信号处理函数

 如果进程为某个信号注册了信号处理函数(也称为信号处理器,上面代码中的 signal_handler 函数),那么当该信号到达时,内核会暂停进程的正常执行流程,转而调用该处理函数。

4.3 忽略信号

  进程可以选择忽略某些信号。这意味着当这些信号到达时,进程不会执行任何特别的操作,而是继续执行其当前的代码路径。然而,需要注意的是,并非所有信号都可以被忽略。例如,SIGKILL和SIGSTOP等信号是不能被忽略的

4.4 阻塞信号

 进程可以选择屏蔽某些信号,以 避免在关键操作期间接收到这些信号。通过调用sigprocmask 等系统调用,进程可以设置其信号屏蔽字,以决定哪些信号能够传递到进程中。被屏蔽的信号将保持在未决状态,直到屏蔽被解除后才会被处理。

4.5 阻塞和忽略的区别

 这两个概念相当容易混淆,从定义上来说:

  • 阻塞是指 进程选择性地阻止某些信号的传递。当这些被阻塞的信号发生时,它们会被内核记录下来(处于未决状态),但不会立即执行信号的处理函数或执行默认操作。
  • 忽略是指进程对收到的某些信号 不执行任何操作,即不调用处理函数也不执行默认操作,而是简单地丢弃这些信号。

大家可以这样理解:信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。 前者是处于未决的状态,后者是被递达后选择了忽略,不做其他处理。


总结

 在这篇文章中介绍了信号的概念,也介绍了信号从哪里来,到哪里去,被接受处理的过程,希望大家有所收获😁。

相关文章:

Linux 操作系统 --- 信号

序言 在本篇内容中&#xff0c;将为大家介绍在操作系统中的一个重要的机制 — 信号。大家可能感到疑惑&#xff0c;好像我在使用 Linux 的过程中并没有接触过信号&#xff0c;这是啥呀&#xff1f;其实我们经常遇到过&#xff0c;当我们运行的进程当进程尝试访问非法内存地址时…...

黑马前端——days09_css

案例 1 页面框架文件 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compati…...

【Python爬虫】技术深度探索与实践

目录 引言 第一部分&#xff1a;Python爬虫基础 1.1 网络基础 1.2 Python爬虫基本流程 第二部分&#xff1a;进阶技术 2.1 动态网页抓取 2.2 异步编程与并发 2.3 反爬虫机制与应对 第三部分&#xff1a;实践案例 第四部分&#xff1a;法律与道德考量 第五部分&#x…...

智启万象|挖掘广告变现潜力,保障支付安全便捷

谷歌致力于为开发者提供 先进的广告变现与支付解决方案 一起回顾 2024 Google 开发者大会 了解如何利用谷歌最新工具和功能 提高变现收入&#xff0c;优化用户体验&#xff0c;保障交易安全 让变现更上一层楼 广告检查器是谷歌 AdMob 平台最新推出的高级测试工具&#xff0c;开…...

函数递归,匿名、内置行数,模块和包,开发规范

一、递归与二分法 一&#xff09;递归 1、递归调用的定义 递归调用&#xff1a;在调用一个函数的过程中&#xff0c;直接或间接地调用了函数本身 2、递归分为两类&#xff1a;直接与间接 #直接 def func():print(from func)func()func() # 间接 def foo():print(from foo)bar…...

Springboot3 整合swagger

一、pom.xml <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-api</artifactId><version>2.1.0</version></dependency> 二、application.yml # SpringDoc配置 # springdoc:swa…...

查看同一网段内所有设备的ip

使用命令提示符&#xff08;CMD&#xff09;进行扫描 查看本机IP地址 首先通过 ipconfig /all 命令查看本机的IP地址&#xff0c;确定你的网段&#xff0c;例如 192.168.1.。 Ping网段内每个IP地址 接着使用循环命令&#xff1a; for /L %i IN (1,1,254) DO ping -w 1 -n …...

Spark MLlib 特征工程(上)

文章目录 Spark MLlib 特征工程(上)特征工程预处理 Encoding:StringIndexer特征构建:VectorAssembler特征选择:ChiSqSelector归一化:MinMaxScaler模型训练总结Spark MLlib 特征工程(上) 前面我们一起构建了一个简单的线性回归模型,来预测美国爱荷华州的房价。从模型效果来…...

《SPSS零基础入门教程》学习笔记——03.变量的统计描述

文章目录 3.1 连续变量&#xff08;1&#xff09;集中趋势&#xff08;2&#xff09;离散趋势&#xff08;3&#xff09;分布特征 3.2 分类变量&#xff08;1&#xff09;单个分类变量&#xff08;2&#xff09;多个分类变量 3.1 连续变量 &#xff08;1&#xff09;集中趋势 …...

2024年杭州市网络与信息安全管理员(网络安全管理员)职业技能竞赛的通知

2024年杭州市网络与信息安全管理员&#xff08;网络安全管理员&#xff09;职业技能竞赛的通知 一、组织机构 本次竞赛由杭州市总工会牵头&#xff0c;杭州市人力资源和社会保障局联合主办&#xff0c;杭州市萧山区总工会承办&#xff0c;浙江省北大信息技术高等研究院协办。…...

SpringBoot参数校验详解

前言 在web开发时&#xff0c;对于请求参数&#xff0c;一般上都需要进行参数合法性校验的&#xff0c;原先的写法时一个个字段一个个去判断&#xff0c;这种方式太不通用了&#xff0c;Hibernate Validator 是 Bean Validation 规范的参考实现&#xff0c;用于在 Java 应用中…...

安全基础学习-SHA-1(Secure Hash Algorithm 1)算法

SHA-1(Secure Hash Algorithm 1)是一种密码学哈希函数,用于将任意长度的输入数据(消息)转换成一个固定长度的输出(哈希值或摘要),长度为160位(20字节)。SHA-1的主要用途包括数据完整性验证、数字签名、密码存储等。 1、SHA-1 的特性 定长输出:无论输入数据长度是多…...

leetcode350. 两个数组的交集 II,哈希表

leetcode350. 两个数组的交集 II 给你两个整数数组 nums1 和 nums2 &#xff0c;请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数&#xff0c;应与元素在两个数组中都出现的次数一致&#xff08;如果出现次数不一致&#xff0c;则考虑取较小值&#xff09;。可…...

基于YOLOv8的缺陷检测任务模型训练

文章目录 一、引言二、环境说明三、缺陷检测任务模型训练详解3.1 PCB数据集3.1.1 数据集简介3.1.2 数据集下载3.1.3 构建yolo格式的数据集 3.2 基于ultralytics训练YOLOv83.2.1 安装依赖包3.2.2 ultralytics的训练规范说明3.2.3 创建训练配置文件3.2.4 下载预训练模型3.2.5 训练…...

【upload]-ini-[SUCTF 2019]CheckIn-笔记

上传图片木马文件后看到&#xff0c;检查的文件内容&#xff0c;包含<? 一句话木马提示 检查的文件格式 用如下图片木马&#xff0c;加上GIF89a绕过图片和<?检查 GIF89a <script languagephp>eval($_POST[cmd])</script> .user.ini实际上就是一个可以由用…...

uniapp条件编译使用教学(#ifdef、#ifndef)

#ifdef //仅在xxx平台使用#ifndef //除了在xxx平台使用#endif // 结束 标识平台APP-PLUSAPPMP微信小程序/支付宝小程序/百度小程序/头条小程序/QQ小程序MP-WEIXIN微信小程序MP-ALIPAY支付宝小程序MP-BAIDU百度小程序MP-TOUTIAO头条小程序MP-QQQQ小程序H5H5APP-PLUS-NVUEApp nv…...

NXP i.MX8系列平台开发讲解 - 4.1.2 GNSS 篇(二) - 卫星导航定位原理

专栏文章目录传送门&#xff1a;返回专栏目录 Hi, 我是你们的老朋友&#xff0c;主要专注于嵌入式软件开发&#xff0c;有兴趣不要忘记点击关注【码思途远】 文章目录 关注星号公众号&#xff0c;不容错过精彩 作者&#xff1a;HywelStar Hi, 我是你们的老朋友HywelStar, 根…...

怎样在 SQL 中对一个包含销售数据的表按照销售额进行降序排序?

在当今数字化商业的浪潮中&#xff0c;数据就是企业的宝贵资产。对于销售数据的有效管理和分析&#xff0c;能够为企业的决策提供关键的支持。而在 SQL 中&#xff0c;对销售数据按照销售额进行降序排序&#xff0c;是一项基础但极其重要的操作。 想象一下&#xff0c;您面前有…...

DIAdem 与 LabVIEW

DIAdem 和 LabVIEW 都是 NI (National Instruments) 公司开发的产品&#xff0c;尽管它们有不同的核心功能和用途&#xff0c;但它们在工程、测试和测量领域中常常一起使用&#xff0c;以形成一个完整的数据采集、分析、处理和报告生成的解决方案。 1. 功能和用途 LabVIEW (Lab…...

UE虚幻引擎可以云渲染吗?应用趋势与挑战了解

虚幻云渲染技术是基于虚幻引擎的云端渲染技术&#xff0c;将虚幻引擎的渲染计算任务通过云计算的方式进行处理和渲染、并将渲染结果传输到终端设备上进行展示。虚幻引擎云渲染技术在近年来得到了迅猛的发展&#xff0c;并在各个领域得到了广泛的应用&#xff0c;包括游戏、电影…...

实战分享:DefenderUI在企业环境中的部署与应用

前言 想象一下&#xff0c;你的电脑就像一座坚固的城堡&#xff0c;但城门却时常被一些不速之客窥探甚至企图入侵&#xff1b;Defender&#xff0c;作为城堡自带的守护者&#xff0c;实力自然不容小觑&#xff1b;但你是否觉得它有时候太过低调&#xff0c;有些隐藏技能还没完…...

中英双语介绍金融经济中的鹰派 (Hawkish)和鸽派 (Dovish)

中文版 在金融和经济政策中&#xff0c;“鹰派”和“鸽派”是两种对货币政策和经济管理有不同立场的群体。 鹰派 (Hawkish) 鹰派倾向于担心通货膨胀的风险&#xff0c;通常支持较高的利率和更紧的货币政策&#xff0c;以防止经济过热和控制物价上涨。具体特征包括&#xff1…...

Android 开发中常用的布局类型及其选择指南

在 Android 开发过程中,选择正确的布局类型对于构建高效、美观且响应式的用户界面至关重要。本文将介绍 Android 中几种最常用的布局类型,并对比它们的特点和适用场景,帮助开发者们做出明智的选择。 1. LinearLayout - 线性布局 特点: LinearLayout 是最基本的布局类型之一…...

短视频SDK解决方案,降低行业开发门槛

美摄科技匠心打造了一款集前沿技术与极致体验于一体的短视频SDK解决方案&#xff0c;它不仅重新定义了短视频创作的边界&#xff0c;更以行业标杆级的短视频特效&#xff0c;让每一帧画面都闪耀不凡光芒。 【技术赋能&#xff0c;创意无限】 美摄科技的短视频SDK&#xff0c;…...

【C++】String常见函数用法

一、string类对象的常见构造 我们可采取以下的方式进行构造&#xff0c;以下是常用的接口&#xff1a; //生成空字符串 string; //拷贝构造函数 string(const string& str); //用C-string来构造string类对象 string(const char* s); //string类对象中包含n个字符c strin…...

LeetCode49.字母异位词分组

题目大意 给你一个字符串数组&#xff0c;请你将字母异位词组合在一起。可以按任意顺序返回结果列表。 字母异位词是由重新排列源单词的所有字母得到的一个新单词。 思路分析 示例 1: 输入: strs ["eat", "tea", "tan", "ate", &…...

Nginx日志按天分割

需求、日志按照天的单位进行分割存储。 如果你直接百度&#xff0c;可能会搜到很多教你用各种脚本或是三方插件来按天分割的&#xff0c;这边我用nginx服务本身来分割日志。 方法一 通过使用 $time_iso8601 变量和 map 指令&#xff0c;实现了日志文件按天分割的功能。以下是…...

文本摘要简介

文本摘要是从一段长文本中提取出最重要的信息&#xff0c;并生成一个简短而有意义的摘要。这个过程可以分为两种主要方法&#xff1a; 抽取式摘要&#xff08;Extractive Summarization&#xff09;&#xff1a;从原文中直接提取出关键句子或段落&#xff0c;组成摘要…...

3.MySQL面试题之Redis 和 Mysql 如何保证数据一致性?

Redis 和 MySQL 数据一致性是分布式系统中的一个常见挑战。保证数据一致性通常涉及几种策略&#xff0c;我会详细解释这些策略并提供相应的代码示例。 先更新数据库&#xff0c;再更新缓存 这种方法先更新 MySQL&#xff0c;然后更新或删除 Redis 缓存。 Transactional publ…...

浅谈TCP协议、UDP协议

一、介绍说明 TCP&#xff08;传输控制协议&#xff09; 面向连接&#xff1a;TCP在数据传输之前必须建立连接。这通过一个称为三次握手的过程来完成&#xff0c;确保连接的两端都准备好进行数据传输。 可靠性&#xff1a;TCP提供可靠的数据传输&#xff0c;确保数据包正确无…...

SQL业务题: 从不订购的客户

1️⃣题目 Customers 表&#xff1a; ---------------------- | Column Name | Type | ---------------------- | id | int | | name | varchar | ---------------------- 在 SQL 中&#xff0c;id 是该表的主键。 该表的每一行都表示客户的 ID 和名…...

怎么直接在PDF上修改内容?随心编辑PDF内容

PDF(Portable Document Format)作为一种专用于阅读而非编辑的文档格式&#xff0c;其设计的核心目的是保持文档格式的一致性&#xff0c;确保文档在不同平台和设备上都能以相同的布局和格式呈现。然而&#xff0c;在实际工作和生活中&#xff0c;我们经常需要对PDF文档进行编辑…...

聊天室项目测试报告

项目介绍 本项目是一个基于Spring Boot框架开发的聊天室应用。一个实时的文本消息交流平台&#xff0c;允许多个用户同时在线聊天。系统采用了Spring Boot作为后端框架&#xff0c;集成了WebSocket技术以实现消息的实时推送与接收提供一个简单、易用且功能完备的在线聊天环境。…...

语音识别(实时语音转录)——funasr的详细部署和使用教程(包括实时语音转录)

阿里达摩院开源大型端到端语音识别工具包FunASR&#xff1a; FunASR提供了在大规模工业语料库上训练的模型&#xff0c;并能够将其部署到应用程序中。工具包的核心模型是Paraformer&#xff0c;这是一个非自回归的端到端语音识别模型&#xff0c;经过手动注释的普通话语音识别…...

【网络编程】TCP机械臂测试

通过w(红色臂角度增大)s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09;按键控制机械臂 注意&#xff1a;关闭计算机的杀毒软件&#xff0c;电脑管家&#xff0c;防火墙 1&#xff09;基于TCP服务器…...

笔记:在WPF中如何注册控件级全局事件和应用程序级全局事件

一、目的&#xff1a;在WPF中如何注册控件级全局事件和应用程序级全局事件 二、实现 应用程序级全局事件 //注册应用程序级全局事件 EventManager.RegisterClassHandler(typeof(Button), Button.ClickEvent, new RoutedEventHandler(ic_event_Click)); 如上代码既会注册全局…...

【Linux系列】telnet使用入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

音视频相关知识

H.264编码格式 音频 PCM就是要把声音从模拟信号转换成数字信号的一种技术&#xff0c;他的原理简单地说就是利用一个固定的频率对模拟信号进行采样。 pcm是无损音频音频文件格式...

数据结构--第七天

递归 -递归的概念 递归其实就是一种解决问题的办法&#xff0c;在C语言中&#xff1a;递归就是函数自己调用自己 -递归的思想 递归的思考方式就是把大事化小的过程 递归的递就是递推的意思&#xff0c;归就是回归的意思 &#xff08;递归是少量的代码完成大量的运算&#xff09…...

代码随想录Day34:62.不同路径、63.不同路径II、343.整数拆分、96.不同的二叉搜索树

62. 不同路径 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&…...

【信息学奥赛一本通】1008:计算(a+b)/c的值

1008&#xff1a;计算(ab)/c的值 时间限制: 1000 ms 内存限制: 66536 KB 提交数:164836 通过数: 142434 【题目描述】 给定3个整数a、b、c&#xff0c;计算表达式abc的值。 【输入】 输入仅一行&#xff0c;包括三个整数a、b、c, 数与数之间以一个空格分开。(&#xff0d;10,…...

使用 jstat 进行 Java 应用程序性能监控

jstat 使用经验笔记 1. 简介 jstat 是 Java 开发工具包 (JDK) 中的一个命令行工具&#xff0c;用于监控 Java 虚拟机 (JVM) 的运行时状态&#xff0c;特别是垃圾回收 (Garbage Collection, GC) 的行为。通过使用 jstat&#xff0c;你可以监控和诊断 Java 应用程序的内存使用情…...

Prompt指令调优大揭秘

Hey&#xff0c;技术达人们&#xff01;今天咱们就来聊聊Prompt指令调优的那些事儿。想象一下&#xff0c;你有一个超级智能的AI小伙伴&#xff0c;但要让它更懂你&#xff0c;更给力&#xff0c;那就得靠点“魔法”——Prompt指令调优。准备好了吗&#xff1f;让我们一探究竟&…...

C语言中的⽂件操作

1. 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进⾏持久化…...

黑马前端——days14_js

案例 1 页面框架文件 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title>&l…...

【自动驾驶】ROS中参数服务器通信(c++)

目录 通信过程新建参数服务器包编写测试文件修改cmakelist:搭配launch文件启动测试及结果 通信过程 1.Talker 设置参数 Talker 通过 RPC 向参数服务器发送参数(包括参数名与参数值)&#xff0c;ROS Master 将参数保存到参数列表中。 2.Listener 获取参数 Listener 通过 RPC 向…...

零基础5分钟上手亚马逊云科技核心云开发知识 - 网络基础

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…...

Unity Recttransform操作

1、拉伸铺满 RectTransform rect GetComponent<RectTransform>();rect.anchorMin Vector2.zero;rect.anchorMax Vector2.one;rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, Screen.width);rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Verti…...

MIT线性代数P5

置换矩阵 置换矩阵是行重新排列的单位矩阵。 置换矩阵用P表示&#xff0c; 性质&#xff1a; n阶置换矩阵共有n!个...

patroni+etcd开启SSL认证(三个节点证书一致 使用openssl命令)

瀚高数据库 目录 环境 文档用途 详细信息 环境 系统平台&#xff1a;Linux x86-64 Red Hat Enterprise Linux 7 版本&#xff1a;14 文档用途 本文主要介绍Patroni架构中如何开启etcd的ssl证书认证。 详细信息 一、前提说明 patroni版本&#xff1a;3.0.2 etcd版本&#x…...