c/c++之信号处理<signal.h>
该库提供了一组用于处理信号的函数和宏。信号是由操作系统或程序本身生成的一种异步事件,用于通知某些事件的发生,例如非法操作、用户中断等。
信号
信号是进程之间通信的重要方式。信号是一种异步通知机制,由操作系统或其他进程发送给当前进程,用于通知当前进程发生了某些事件,该进程程序捕获到这个信号后触发相应的处理逻辑。信号捕捉是指进程在接收到信号后采取的行动,而信号处理则是指对接收到的信号进行适当的处理逻辑。
信号捕捉
当信号的处理动作是用户自定义的函数,并且在信号到达时调用该函数,这被称为信号捕捉。信号处理函数运行在用户空间。
信号处理函数:用于捕获和处理各种信号
①signal
设置信号处理程序
函数原型:
void (*signal(int sig, void (*func)(int)))(int);
参数:
- int sig:信号编号
- void (*func)(int):一个函数指针,指向接受一个int参数并返回void的函数
注意:
void (*)(int)
这是一个函数指针,指向的函数接受一个int参数并返回void,即返回的是当前绑定的信号处理函数,对于下面的例子中的prevSignalHandler就可以认为是函数mySignalHandler。
示例:
void mySignalHandler(int sig) { ....... }
void newSignalHandler(int sig) { ..... }
void (*prevSignalHandler)(int) = signal(SIGINT, mySignalHandler);
signal(SIGINT, newSignalHandler);
signal(SIGINT, prevSignalHandler);
说明:当用户按下 Ctrl+C 发送 SIGINT 信号时,程序会调用相应的信号处理函数,
例如在程序中,mySignalHandler和 newSignalHandler 就是处理 SIGINT 信号的处理函数。
②raise
会向当前进程发送指定的信号,并触发信号的处理机制。如果进程对信号sig有自定义的信号处理函数,则调用该处理函数。如果信号未被捕获,操作系统会执行默认行为
函数原型:
int raise(int sig);
参数:
sig:要发送的信号编号,例如SIGINT、SIGTERM等,信号编号通常定义在<signal.h><csignal>中
返回值:
成功时返回0,失败时返回非零值,通常不会失败,因为信号是发送给自己的进程。
示例:
触发信号处理函数
#include <signal.h>
#include <stdio.h>void signalHandler(int sig) {if (sig == SIGINT) {printf("Received SIGINT signal\n");}
}int main() {signal(SIGINT, signalHandler); // 注册 SIGINT 信号处理函数raise(SIGINT); // raise 发送信号 SIGINT,触发信号处理函数 signalHandlerreturn 0;
}
信号宏:用于表示不同类型的信号
示例:
以SIGTERM为例
当执行下面代码时,在另一个终端中执行kill -SIGTERM 1234(执行该代码的进程号)时会向执行该代码的进程发送一个终止信号,执行该代码的进程检测到该信号后会执行signalHandler函数
#include <signal.h>
#include <stdio.h>
#include <unistd.h>void signalHandler(int sig) { if (sig == SIGTERM) {printf("Received SIGTERM signal\n");}
}int main() {signal(SIGTERM, signalHandler); // 注册 SIGTERM 信号的处理函数printf("Program is running. PID: %d\n", getpid());while (true) { // 程序会持续运行,等待信号sleep(1); // 使程序在每个循环中暂停,避免占用过多 CPU}return 0;
}
或者直接通过raise向自身进程发送终止信号,此时也会调用signalHandler函数
#include <signal.h>
#include <stdio.h>
#include <unistd.h>void signalHandler(int sig) { // signalHandler 应该有一个 int 参数if (sig == SIGTERM) {printf("Received SIGTERM signal\n");}
}int main() {signal(SIGTERM, signalHandler); // 注册 SIGTERM 信号的处理函数printf("Program is running. Sending SIGTERM to itself...\n");sleep(2); // 等待一段时间,模拟程序运行raise(SIGTERM); // 向自己发送 SIGTERM 信号while (true); // 程序会持续运行,等待信号return 0;
}
信号集操作函数
①sigemptyset和sigfillset
sigemptyset:用于初始化信号集为空
int sigemptyset(sigset_t* set);
sigfillset:用于将系统所支持的所有信号都填充到信号集中
int sigfillset(sigset_t* set);
示例:
#include <iostream>
#include <csignal> // 提供 sigset_t,sigemptyset,sigfillset 等函数
#include <cstring> // 提供 strerrorint main() {// 定义一个信号集对象sigset_t sigset;// 1. 使用 sigemptyset 将信号集初始化为空if (sigemptyset(&sigset) != 0) {std::cerr << "Failed to initialize empty signal set: " << strerror(errno) << std::endl;return 1;}std::cout << "Signal set initialized to empty successfully." << std::endl;// 此时,sigset 中不包含任何信号// 2. 使用 sigfillset 将系统支持的所有信号加入到信号集中if (sigfillset(&sigset) != 0) {std::cerr << "Failed to fill signal set: " << strerror(errno) << std::endl;return 1;}std::cout << "Signal set filled with all signals successfully." << std::endl;// 此时,sigset 中包含了系统支持的所有信号return 0;
}
②sigaddset和sigdelset
sigaddset:用于将指定信号添加到信号集中
int sigaddset(sigset_t* set, int signum);
//将信号SIGINT加入到信号集中
sigaddset(&set, SIGINT);
sigdelset:用于将指定信号从信号集中删除
int sigdelset(sigset_t* set, int signum);
//从信号集中删除SIGINT这个信号
sigdelset(&set, SIGINT);
③sigismember
检查指定信号是否在信号集中
返回值:
=1在
=0不在
int ret = sigismember(&sigset, SIGINT);
if (ret == 1) {std::cout << "SIGINT is in the signal set (unexpected)." << std::endl;
} else if (ret == 0) {std::cout << "SIGINT is NOT in the signal set (expected)." << std::endl;
} else {std::cerr << "Error checking signal set: " << strerror(errno) << std::endl;return 1;
}
④sigprocmask
用于设置或查询当前的信号屏蔽
int sigprocmask(int how, const sigset_t* set, sigset_t* oldset);
根据how的选择将set向信号屏蔽字中设置,并将查询到的老的信号屏蔽字存储到oldset中
参数:
how:指定如何修改信号屏蔽字
- SIG_BLOCK:将set中的信号添加到当前信号屏蔽字中,阻塞这些信号
- SIG_UNBLOCK:将set中的信号从当前信号屏蔽字中移除,解除阻塞
- SIG_SETMASK用set中的信号集完全替换当前的信号屏蔽字。
注意:信号屏蔽字是指一个进程中用于记录当前被阻塞的信号集和的数据结构,它是由操作系统内核维护的用来表示哪些信号在当前进程中 被阻塞(即不会被立即传递和处理),而是被暂时挂起。
set:指向一个sigset_t类型的信号集,表示要修改或设置的信号集合。如果为NULL表示不修改信号屏蔽字,仅查询当前屏蔽字,查询结果存储在oldset中
oldset:指向一个sigset_t类型的信号集,用于存储调用sigprocmask之前的信号 屏蔽字。如果不需要保存旧的信号屏蔽字,可以传入NULL。
使用 sigprocmask 屏蔽 SIGINT 信号
if (sigprocmask(SIG_BLOCK, &set, &oldset) != 0) {std::cerr << "Failed to block SIGINT: " << strerror(errno) << std::endl;return 1;
}
std::cout << "SIGINT is now blocked. Try pressing Ctrl+C, it won't terminate the program." << std::endl;// 让程序睡眠 10 秒,此时 SIGINT 被屏蔽,按 Ctrl+C 没反应
sleep(10);恢复之前的信号屏蔽字(解除 SIGINT 屏蔽)
if (sigprocmask(SIG_SETMASK, &oldset, nullptr) != 0) {std::cerr << "Failed to restore old signal mask: " << strerror(errno) << std::endl;return 1;
}
std::cout << "SIGINT is now unblocked. Try pressing Ctrl+C again." << std::endl;// 再睡眠 10 秒,这时按 Ctrl+C,会触发信号处理器
sleep(10);
⑤sigpending
获取当前进程的未决信号集。未决信号集包含了所有当前被阻塞且已经产生的信号。这些信号尚未被交付给进程,因为他们被当前的信号屏蔽字阻塞。(当信号被屏蔽时,发送信号会导致信号进入未决信号集)。
int sigpending(sigset_t* pending);
pending:函数会将未决信号集存储到这个变量中
int main() {sigset_t set, pending;// 注册 SIGUSR1 的信号处理函数if (signal(SIGUSR1, signalHandle) == SIG_ERR) {std::cerr << "Failed to register signal handler: " << strerror(errno) << std::endl;return 1;}// 初始化信号集为空if (sigemptyset(&set) != 0) {std::cerr << "Failed to initialize signal set: " << strerror(errno) << std::endl;return 1;}// 将 SIGUSR1 加入信号集if (sigaddset(&set, SIGUSR1) != 0) {std::cerr << "Failed to add SIGUSR1 to signal set: " << strerror(errno) << std::endl;return 1;}// 屏蔽 SIGUSR1 信号if (sigprocmask(SIG_BLOCK, &set, nullptr) != 0) {std::cerr << "Failed to block SIGUSR1: " << strerror(errno) << std::endl;return 1;}std::cout << "SIGUSR1 is now blocked. Raising SIGUSR1..." << std::endl;// 向自己发送一个 SIGUSR1 信号if (raise(SIGUSR1) != 0) {std::cerr << "Failed to raise SIGUSR1: " << strerror(errno) << std::endl;return 1;}// 查询当前挂起(pending)的信号if (sigpending(&pending) != 0) {std::cerr << "Failed to get pending signals: " << strerror(errno) << std::endl;return 1;}// 检查 SIGUSR1 是否在挂起的信号集中int ret = sigismember(&pending, SIGUSR1);if (ret == 1) {std::cout << "SIGUSR1 is pending (blocked and waiting to be handled)." << std::endl;} else if (ret == 0) {std::cout << "SIGUSR1 is NOT pending." << std::endl;} else {std::cerr << "Error checking pending signals: " << strerror(errno) << std::endl;return 1;}// 解除 SIGUSR1 的屏蔽,允许它被处理if (sigprocmask(SIG_UNBLOCK, &set, nullptr) != 0) {std::cerr << "Failed to unblock SIGUSR1: " << strerror(errno) << std::endl;return 1;}std::cout << "SIGUSR1 unblocked. Signal handler should now be invoked." << std::endl;// 给操作系统一点时间处理解除后的信号sleep(1);return 0;
}
⑥sigpsuspend
用于临时替换进程的信号屏蔽字并等待某个信号到达。当信号到达并被处理后,sigsuspend会恢复原来的信号屏蔽字。
int sigsuspend(const sigset_t* mask);
mask:指向一个信号集的指针,用于临时设置进程的信号屏蔽字。在调用sigsuspend时,进程的信号屏蔽字会被替换为mask指定的信号集。
注意:sigsuspend不会永久修改信号屏蔽字,函数返回后信号屏蔽字会自动恢复。
void signalHandle(int signum) {std::cout << "Signal handler called with signal " << signum << "!" << std::endl;
}int main() {sigset_t set, newmask, oldmask;// 注册 SIGUSR1 的信号处理函数if (signal(SIGUSR1, signalHandle) == SIG_ERR) {std::cerr << "Failed to register signal handler: " << strerror(errno) << std::endl;return 1;}// 初始化信号集为空if (sigemptyset(&set) != 0) {std::cerr << "Failed to initialize set: " << strerror(errno) << std::endl;return 1;}// 将 SIGUSR1 加入信号集if (sigaddset(&set, SIGUSR1) != 0) {std::cerr << "Failed to add SIGUSR1 to set: " << strerror(errno) << std::endl;return 1;}// 将 SIGUSR1 屏蔽,阻塞它if (sigprocmask(SIG_BLOCK, &set, &oldmask) != 0) {std::cerr << "Failed to block SIGUSR1: " << strerror(errno) << std::endl;return 1;}std::cout << "SIGUSR1 is now blocked. Ready to suspend and wait for signal..." << std::endl;// 初始化新的信号集:newmask,不屏蔽任何信号if (sigemptyset(&newmask) != 0) {std::cerr << "Failed to initialize newmask: " << strerror(errno) << std::endl;return 1;}// 在调用 sigsuspend 前发送 SIGUSR1 信号if (raise(SIGUSR1) != 0) {std::cerr << "Failed to raise SIGUSR1: " << strerror(errno) << std::endl;return 1;}// 使用 sigsuspend 临时用 newmask 替换信号屏蔽字// 当前屏蔽的 SIGUSR1 被临时放开,允许信号处理函数被执行std::cout << "Calling sigsuspend, waiting for signal..." << std::endl;if (sigsuspend(&newmask) == -1 && errno != EINTR) {std::cerr << "sigsuspend error: " << strerror(errno) << std::endl;return 1;}std::cout << "sigsuspend returned after handling the signal." << std::endl;// 恢复之前的信号屏蔽字if (sigprocmask(SIG_SETMASK, &oldmask, nullptr) != 0) {std::cerr << "Failed to restore old signal mask: " << strerror(errno) << std::endl;return 1;}std::cout << "Signal mask restored. Program exiting normally." << std::endl;return 0;
}
高级信号处理函数
sigaction
检查或修改与指定信号相关联的处理动作(可同时两种操作)
函数原型:
int sigaction(int signum, const struct signaction* act, struct signaction* oldact);
参数:
signum:指出要捕获的信号类型
act:指定信号新的处理方式
oldact:如果不为NULL的话,oldact用于存储当前信号先前的处理方式
返回值:
0表示成功,-1表示有错误发生
相关结构体:
①sigaction
struct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int, siginfo_t*, void*);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);
}
struct sigaction成员:
- sa_handler:指向信号处理函数的指针。如果设置为非空,当信号signum到达时会调用这个函数。该函数接收一个参数,该参数是信号编号。
- sa_sigaction:指向带扩展信息的信号处理函数的指针。如果sa_flags中设置了SA_SIGINFO标志,那么会使用sa_sigaction而不是sa_handler作为信号处理函数,该函数接收三个参数,参数一int为信号编号,参 数二siginfo_t*指向包含信号附加信息的结构体,参数三void*指向用户上下文信息的指针(通常为ucontext_t)。
注意:在某些系统中sa_handler和sa_sigaction被放在联合体中,因此使用时不要同时设置。
- sa_mask:在信号处理程序运行期间要屏蔽的信号集和。在信号处理执行期间,会自动屏蔽signum信号以防止递归。通过sa_mask,可以指定额外的信号,在处理函数执行期间暂时屏蔽这些信号。
- sa_flags:控制信号处理行为的标志,可以是多个标志的按位或组合
-
sa_flags常见标志位:
-
- sa_restorer:用于恢复信号处理的函数。此字段通常未使用,留为空,在现代linux系统中,由内核负责信号处理的恢复操作,因此不需要设置此字段。
- ②siginfo_t
-
用于在信号处理过程中提供关于新号的详细信息。
-
struct siginfo_t成员
-
- 示例一:
-
void my_handler(int sig) { // ........ }void my_sigaction(int sig, siginfo_t* info, void* context) { // ........... }int example1() {struct sigaction act;act.sa_handler = my_handler;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask, SIGTERM); // 屏蔽SIGTERMact.sa_flags = SA_RESTART;sigaction(SIGINT, &act, nullptr); // 安装信号处理程序return 0; }
示例二:
-
std::atomic<int> download_progress{0}; std::atomic<bool> stop_download{false};// 信号处理函数SIGUSR1:显示下载速度 void show_progress(int sig, siginfo_t* info, void* context) {std::cout << sig << " download progress " << download_progress.load() << std::endl;std::cout << "Sender PID: " << info->si_pid << std::endl;std::cout << "Sender UID: " << info->si_uid << std::endl; }// 信号处理函数SIGUSR2:强制停止下载 void stop_handler(int sig, siginfo_t* info, void* context) {std::cout << "Download will be stopped" << std::endl;stop_download.store(true); }// 下载的函数 void simulate_download() {std::cout << "Start download" << std::endl;while (download_progress.load() < 100 && !stop_download.load()) {download_progress.fetch_add(5);std::cout << "Current progress: " << download_progress.load() << "%" << std::endl;sleep(1);}if (stop_download.load()) {std::cout << "Stop download" << std::endl;} else {std::cout << "Download successfully" << std::endl;} }int example2() {struct sigaction sa_usr1, sa_usr2;// 初始化SIGUSR1的信号处理std::memset(&sa_usr1, 0, sizeof(sa_usr1));sa_usr1.sa_sigaction = show_progress; // 设置为带扩展信息的处理函数sigemptyset(&sa_usr1.sa_mask); // 不额外屏蔽其他信号sa_usr1.sa_flags = SA_SIGINFO; // 启用扩展信息处理if (sigaction(SIGUSR1, &sa_usr1, nullptr) == -1) {perror("Error happen");return 1;}// 初始化SIGUSR2的信号处理std::memset(&sa_usr2, 0, sizeof(sa_usr2));sa_usr2.sa_sigaction = stop_handler;sigemptyset(&sa_usr2.sa_mask);sa_usr2.sa_flags = SA_SIGINFO;if (sigaction(SIGUSR2, &sa_usr2, nullptr) == -1) {perror("Error happen");return 1;}simulate_download();return 0; }
相关文章:
c/c++之信号处理<signal.h>
该库提供了一组用于处理信号的函数和宏。信号是由操作系统或程序本身生成的一种异步事件,用于通知某些事件的发生,例如非法操作、用户中断等。 信号 信号是进程之间通信的重要方式。信号是一种异步通知机制,由操作系统或其他进程发送给当前进…...
基于PyTorch的图像分类特征提取与模型训练文档
概述 本代码实现了一个基于PyTorch的图像特征提取与分类模型训练流程。核心功能包括: 使用预训练ResNet18模型进行图像特征提取 将提取的特征保存为标准化格式 基于提取的特征训练分类模型 代码结构详解 1. 库导入 import torch import torch.nn as nn import…...
DDoS vs CC攻击:哪种对服务器威胁更大?
引言 DDoS(分布式拒绝服务)与CC(Challenge Collapsar)攻击是两种常见的网络攻击手段,均会导致服务器资源耗尽、服务中断。但它们的攻击原理、防御难度及危害程度存在显著差异。本文将从技术原理、攻击效果、防御成本等…...
Weiss Robotics的WPG与WSG系列紧凑型机器人夹爪,精准、灵活、高效
在自动化和智能制造领域,Weiss Robotics 以其创新的智能抓取系统而受到广泛认可。本文将重点介绍 Weiss Robotics 的两大产品系列:WPG 系列和 WSG 系列。这些产品系列凭借其先进的技术特性,为各行各业的自动化需求提供了高效、灵活的解决方案…...
引力透镜效应添加光线弯曲程度可视化层的MATLAB代码
物理实现要点: 雅可比矩阵计算 通过数值梯度计算偏转场的空间导数: 放大率μ反映像的亮度增强倍数 动态范围处理 使用对数压缩μ值范围:μ_vis log10(1μ),避免高放大率区域饱和 多物理量联合显示 红圈标注爱因…...
OpenCV 图形API(71)图像与通道拼接函数-----从图像(GMat)中裁剪出一个矩形区域的操作函数 crop()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 裁剪一个2D矩阵。 该函数根据给定的 cv::Rect 裁剪矩阵。 输出矩阵必须与输入矩阵具有相同的深度,大小由给定的矩形大小指定。 注意…...
tarjan缩点+强联通分量
【模板】缩点https://www.luogu.com.cn/problem/P3387 首先我们要理解这道题为什么要用缩点 题目说的是有向图,如果无环的话就可以用DP来解决了 由于可以走重复的点,所以一个环上的点可以看成是一个点,它的点权就等于该环上所有点的点权之…...
tornado_登录页面(案例)
目录 1.基础知识编辑 2.脚手架(模版) 3.登录流程图(processon) 4.登录表单 4.1后(返回值)任何值:username/password (4.1.1)app.py (4.1.2ÿ…...
Educational Codeforces Round 178 (Rated for Div. 2)
ABC 略 D n个数互质,即n个数都是质数,预处理前4e5个质数,原排列从大到小排序求前缀和,质数求前缀和,从后往前循环第一个前者前缀和能大于等于后者就是留下的i个数。 #include<bits/stdc.h> #define int long …...
从Transformer原理角度来看,prompt设置输出字数限制会生效的原因
从Transformer原理角度来看,prompt设置输出字数限制会生效的原因 1. 生成过程的控制 Transformer在生成文本时是一个自回归的过程,它从起始标记开始,逐个生成下一个单词或标记。在这个过程中,模型会根据已经生成的文本和自身的参数来预测下一个可能的标记的概率分布。当设…...
WEB漏洞--CSRF及SSRF案例
CSRF案例 原理 检测是否存在CSRF(跨站请求伪造)漏洞 1. 手动测试 构造恶意请求:创建一个恶意网页或电子邮件,包含指向目标网站的恶意请求(如更改密码或发送消息的URL)。诱使用户访问该恶意请求,…...
Android开发——实现一个计算器
目录 代码讲解 activity_calculator.xmld代码讲解 1. 根布局(LinearLayout) 2. 显示区域(TextView) 3. 按钮区域(GridLayout) 4. 清除和删除按钮 5. 数字和操作符按钮 6. 其他行的按钮 7. 最后一行…...
23G显存可以跑多大尺寸的Qwen3?
随着阿里Qwen3系列大模型的发布,开发者们对如何在有限显存下部署不同尺寸的模型尤为关注。本文基于Qwen3的技术特性和实际测试数据,探讨在23G显存环境下可运行的模型选择及优化策略。 不过由于咱财力有限,只有一张A100,还不是空的,目前只有23G的显存。 那么这23G显存能跑…...
网络通讯【QTcpServer、QTcpSocket、QAbstractSocket】
目录 QTcpServer class简单描述成员函数和信号 QTcpSocket Class详细描述成员函数和信号 QAbstractSocket Class详细描述成员函数和信号成员函数说明文档 QT实现服务器和客户端通讯服务器端:通讯流程原代码 客户端通信流程原代码 QTcpServer class header: #includ…...
std::functional 类是干什么用的?
author: hjjdebug date: 2025年 04月 29日 星期二 15:54:53 CST description: std::functional 类是干什么用的? 文章目录 1.functional 对象的概念2.functional 对象存在的意义2.1 为什么要把接口再封一层?2.2 c中函数参数可以不用回调函数, 而改用func…...
人事管理系统6
模糊查询 DepartmentMapper.xml : <select id"findDepartmentListByName" resultMap"BaseResultMap"> select <include refid"Base_Column_List"/> from department where dname like %${dname}% /*where dname like con…...
链表的中间节点
这题需要用到快慢指针的思想,快指针叫fast,慢指针是slow,快指针每次往后移两个节点,slow只移动一个节点,这样子fast的速度是slow的两遍,当fast遍历完链表,slow才遍历一半,正好就在中…...
【学习学学】城市群与都市圈是什么?怎么
城市群与都市圈是什么?怎么发展 这些年城市群,都市圈的概念被逐渐提了出来,也是未来我国即将重点发展的对象之一。 因此,身边有一些朋友在问,城市群与都市圈有什么区别?哪个对城市发展影响更大?…...
【深度学习与大模型基础】第14章-分类任务与经典分类算法
Part 1:什么是分类任务? 1.1 分类就是“贴标签” 想象你有一堆水果,有苹果🍎、橘子🍊、香蕉🍌,你的任务是让机器学会自动判断一个新水果属于哪一类——这就是分类(Classification&…...
第十五章:预训练大语言模型
目录 15.1 数据准备 15.1.1 数据预处理 15.1.2 数据调度 15.2 模型架构 15.2.1 主流架构 一、编码器架构(Encoder-only,以 BERT 为代表) 核心特点: 代表模型:BERT、RoBERTa、ALBERT 典型应用: 二…...
万象生鲜配送系统代码2025年4月29日更新日志
亲爱的用户:万象生鲜配送系统始终致力于为您提供更优质、高效的服务体验。经过我们技术团队的不懈努力,万象生鲜配送系统在 2025 年 4 月迎来了一次重大更新。本次更新涵盖了多个方面,包括功能新增、性能优化以及问题修复,旨在进一…...
Mac 创建QT按钮以及一些操作
在创建QT项目好 后我们打开mainwindow.cpp,下面所示的代码都是在这个cpp文件里面因为它是窗口的入口函数 #include "mainwindow.h" #include "ui_mainwindow.h" #include<QPushButton>//按钮的头文件MainWindow::MainWindow(QWidget *pa…...
C++学习之shell高级和正则表达式
目录 1.正则表达式 2.C中使用正则 3.复习 4.sort命令 5.uniq命令 6.wc命令 7.grep命令 8.find命令 9.xargs命令 10.sed命令 11.awk命令 12.crontab 1.正则表达式 1 管道 使用| 将多个命令拼接在一起 原理,就是将前一个命令的标准输出作为后一个…...
SpringBoot获取用户信息常见问题(密码屏蔽、驼峰命名和下划线命名的自动转换)
文章目录 一、不返回password字段二、返回的createTime和updateTime为空原因解决:开启驼峰命名和下划线命名的自动转换 一、不返回password字段 在字段上面添加JsonIgnore注解即可 JsonIgnore // 在把对象序列化成json字符串时,忽略该字段 private Str…...
优化PCB Via Stub系列(2) – 运用U-Turn Via设计破解阻抗匹配困境,改善信号完整性
在PCB设计中,往往透过制程改善如背钻、盲孔或埋孔,来消除不必要的Via stub,可是多出来的制造成本会压低产品的毛利,可是又有什么办法可以不透过制程改善以缩小Via stub带来的SI困扰呢? 本周我们来讲从Layout布局的角度…...
飞鸟游戏模拟器 1.0.3 | 完全免费无广告,内置大量经典童年游戏,重温美好回忆
飞鸟游戏模拟器是一款专为安卓用户设计的免费游戏模拟器,内置了大量经典的童年游戏。该模拟器拥有丰富的游戏资源,目前已有约20,000款游戏,包括多种类型如冒险、动作、角色扮演等。用户可以直接搜索查找想要玩的游戏进行下载并启动。游戏库中…...
钓鱼网页散播银狐木马,远控后门威胁终端安全
在当今网络环境下,许多人都有通过搜索引擎下载应用程序的习惯,虽然这种方式简单又迅速,但这也可能被不法分子所利用,通过设置钓鱼网站来欺骗用户。这些钓鱼网站可能会通过各种方式吸引用户点击,从而进行病毒的传播&…...
一文读懂 JavaScript 中的深浅拷贝
在 JavaScript 编程里,深浅拷贝是处理数据时极为关键的概念。理解它们的差异,能帮我们规避许多数据操作上的 “陷阱”。今天,咱们就借助简单的 “abc” 相关示例,深入探索深浅拷贝的奥秘,并且通过在浏览器控制台输出结…...
5G技术在工业4.0中的应用:连接未来,驱动智能制造
5G技术在工业4.0中的应用:连接未来,驱动智能制造 引言 工业4.0,作为第四次工业革命的核心,已经在全球范围内掀起了智能制造的浪潮。它不仅包括了自动化生产、智能物流、云计算和大数据的应用,更是融合了互联网、物联网…...
驱动开发硬核特训 · Day 25 (附加篇):从设备树到驱动——深入理解Linux时钟子系统的实战链路
一、前言 在嵌入式Linux开发中,无论是CPU、外设控制器,还是简单的GPIO扩展器,大多数硬件模块都离不开时钟信号的支撑。 时钟子系统(Clock Subsystem),作为Linux内核中基础设施的一部分,为设备…...
数据结构---单链表的增删查改
前言: 经过了几个月的漫长岁月,回头时年迈的小编发现,数据结构的内容还没有写博客,于是小编赶紧停下手头的活动,补上博客以洗清身上的罪孽 目录 前言 概念: 单链表的结构 我们设定一个哨兵位头节点给链…...
【codeforces 2104D,E】欧拉筛,字符串上dp
【codeforces 2104D,E】欧拉筛,字符串上dp Problem - D - Codeforces 题意: 给定一个长度为 n n n的数组 a 1 , a 2 , . . . , a n a_1, a_2, ... , a_n a1,a2,...,an,其中 2 ≤ a i ≤ 1 0 9 2 \leq a_i \leq 10^9 2≤…...
UEC++第15天|番茄插件、实现跳跃、实现背景运动
这是flyBird的第二天,做了一些简单的功能,明天继续更新 vs的番茄插件 在visual stdudio里使用可以帮助代码补全,这一篇博客写的不错,大家可以参考一下。VS2019 安装番茄助手(Visual Assist x 插件)攻略_vs…...
论文笔记-基于多层感知器(MLP)的多变量桥式起重机自适应安全制动与距离预测
《IET Cyber-Systems and Robotics》出版山东大学 Tenglong Zhang 和 Guoliang Liu 团队的研究成果,文章题为“Adaptive Safe Braking and Distance Prediction for Overhead Cranes With Multivariation Using MLP”。 摘要 桥式起重机的紧急制动及其制动距离预测是…...
[论文阅读]Adversarial Semantic Collisions
Adversarial Semantic Collisions Adversarial Semantic Collisions - ACL Anthology Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing (EMNLP) 对抗样本是相似的输入但是产生不同的模型输出,而语义冲突是对抗样本的逆…...
Redis Sentinel 和 Redis Cluster 各自的原理、优缺点及适用场景是什么?
我们来详细分析下 Redis Sentinel (哨兵) 和 Redis Cluster (集群) 这两种方案的原理和使用场景。 Redis Sentinel (哨兵) 原理: Sentinel 本身是一个或一组独立于 Redis 数据节点的进程。它的核心职责是监控一个 Redis 主从复制 (Master-Slave) 架构。多个 Sentinel 进程协同…...
面向人工智能、量子科技、人形机器人等产业,山东启动制造业创新中心培育认定
从山东省工业和信息化厅了解到,2025年山东省制造业创新中心培育和认定已启动,重点面向全省传统优势产业、新兴产业及未来产业等领域,鼓励具备条件的龙头企业牵头创建省制造业创新中心。 今年,山东重点面向全省冶金、化工、轻工、…...
无锡哲讯科技:SAP财务系统——赋能企业智慧财务管理
数字化时代,财务管理的新挑战 在全球化竞争和数字经济快速发展的背景下,企业财务管理正面临前所未有的挑战。传统的财务核算方式效率低下、数据孤岛严重、决策滞后,难以满足现代企业高效运营的需求。如何实现财务数据的实时整合࿱…...
Linux命令使用记录(自用)
阿里开源镜像站:https://developer.aliyun.com/mirror/?spma2c6h.13651102.0.0.6c2a1b11I9pmUD&serviceTypemirror&tag top命令 top [选项] -p 只显示某个进程的信息 -d 设置刷新时间,默认是5s -c 显示产生进程的完整命令,默认是进程…...
Spring Security 的 CSRF 防护机制
CSRF:跨站请求伪造(Cross-Site Request Forgery) Spring Security 中的 .csrf() 是用来开启或配置这种保护机制,防止恶意网站“冒充用户”向你的网站发起请求。 一、CSRF 攻击原理简要 CSRF 的典型攻击场景如下: 用…...
跨平台项目部署全攻略:Windows后端+Mac前端在服务器的协同实战
当你的后端(Flask+MySQL,Windows开发)与前端(Vue,Mac开发)需要统一部署到服务器并实现交互时,完全可以通过「跨平台适配+反向代理」方案实现。本文将分步骤讲解如何在 Linux服务器(推荐)或 Windows服务器 上部署,并解决跨平台兼容性、跨域请求等核心问题。 一、技术…...
第八章 磁盘管理未完待续
1.磁盘管理 磁盘简介 名词:磁盘/硬盘/disk 存储设备类型从工作原理区分 机械 机械硬盘即是传统普通硬盘,主要由:盘片,磁头,盘片转轴及 控制电机,磁头控制器,数据转换器,接口&…...
杰理AC79-WiFi 的 AP、STA 和 Monitor 模式
WiFi 的 AP、STA 和 Monitor 模式是无线网卡的不同工作模式,它们的区别如下: AP 模式(Access Point 模式,接入点模式) 功能:将有线网络转换为无线网络,允许其他无线设备连接到该网络ÿ…...
MAC安装unar并解压.rar文件
MAC上默认解压.zip文件,对.rar文件进行解压需要安装专门对软件。本文记录如何在命令行安装unar并对.rar文件进行解压。 命令行安装 brew install unar打印如下log则安装成功 使用brew list unar检查是否安装成功 brew list unar使用unar解压 unar 文件名.rar...
`nmi_watchdog` 与 `softlockup_panic` 的区别与关系
1. 功能区别 参数作用触发条件影响nmi_watchdog启用 NMI(不可屏蔽中断)看门狗检测 CPU 是否长时间不执行调度(软死锁)仅记录警告(默认),需配合 softlockup_panic 才会触发 panicsoftlockup_pan…...
【Bash】可以请您解释性地说明一下“2>1”这个语法吗?
Qwen3-235B 当然可以!我们一步步拆解 2>&1 的含义,用生活化的例子来理解它: 🧠 前提知识:三个“水流通道” 在 Linux/Unix 系统中,程序运行时有三种默认的“水流通道”: 标准输入&…...
打造美观 API 文档:Spring Boot + Swagger 实战指南
目录 打造美观 API 文档:Spring Boot Swagger 实战指南导语一、Swagger 简介二、Spring Boot 2 集成 Swagger1. 添加依赖2. 配置 Swagger3. 访问 Swagger UI 三、Spring Boot 3 集成 Swagger1. 添加依赖2. 配置 Swagger3. 访问 Swagger UI 四、多种接口文档风格展示…...
如何在 Android 上恢复已删除的照片?:简短指南
没有什么比不小心从 Android 智能手机中删除所有照片更糟糕的了。这样,除非您在重置之前已经备份了数据,否则您的所有照片都会消失。如果您忘记备份照片,您仍然可以按照一些简单的技术在 Android 设备上恢复已删除的照片。 如何在 Android 上…...
第十六届蓝桥杯大赛网安组--几道简单题的WP
目录 1. ezEvtx 2.flowzip 3.Enigma 4.星际XML解析器 1. ezEvtx 题目内容 EVTX文件是Windows操作系统生成的事件日志文件,用于记录系统、应用程序和安全事件。(本题需要选手找出攻击者访问成功的一个敏感文件,提交格式为flag{文件名},其中…...
Element:Cheack多选勾选效果逻辑判断
效果展示 取消子级勾选,父级的勾选效果 代码合集 (1)组件代码 fromlist.cheackType 类型,permissio表示是权限. fromlist:[{id:1,children:[{...}]},...]传递的数据大致结构 <!-- 操作权限 --><template v-if"…...