信号保存和信号处理
目录
信号保存中重要的概念
内核中信号的保存
对sigset_t操作的函数
对block,pendding,handler三张表的操作
sigpromask
编辑
sigpending
是否有sighandler函数呢?
案例
信号处理
操作系统是如何运行的?
硬件中断
时钟中断
软中断
死循环
缺⻚中断?内存碎⽚处理?除零野指针错误?
理解用户态和内核态
信号的自定义捕捉
sigaction
验证阻塞信号
处理完解除对信号的阻塞
验证在处理前将pending表清零
验证sa_mask的作用
可重入函数
案例
volatile
SIGCHLD信号
waitpid补充
验证子进程退出会给父进程发送SIGCHLD信号
基于信号对子进程回收
问题1:
解决方法循环回收
问题2:
信号保存中重要的概念
信号捕捉的三种方式:1.默认 SIG_DFL default
2.忽略 SIG_ING ingore
3.自定义
信号递达:实际执行信号的处理动作
信号未决:信号从产生到递达的状态
信号阻塞:进程可以阻塞某个信号 -->阻塞/屏蔽特定信号,信号产生了,一定把信号pendding(保存),并且信号永远不递达,除非解除阻塞。
os信号的保存都与以上的三个概念有关
阻塞 vs 忽略
阻塞发生在为信号递达之前
忽略发生在信号递达
内核中信号的保存
内核数据结构示意图
pending:信号未决
block: 信号阻塞
handler:信号递达
进程维护了以上的结构,所以进程是可以识别信号的。
以后对进程信号的操作都是为绕着这三张表展开的。
内核中的相应的数据结构
sigset_t 是信号集,也是信号屏蔽字(signal mask)(有block,pending)
类似umask
对sigset_t操作的函数
对block,pendding,handler三张表的操作
sigpromask
读取/修改进程屏蔽字 block表
set:进程中的block表修改基于set
oldset:修改前block表的模样
how:以何种方式修改mask(block表)
1. SIG_BLOCK: mask = mask | set 新增
2.SIG_UNBLOCK : mask = mask & ~set 去除指定信号
3.SIG_SETMASK: mask = set 覆盖
sigpending
通过该函数可以知道pending表的情况
但为什么不设置一个输入型参数,修改pending表呢?
因为信号的产生都是在修改pending表
是否有sighandler函数呢?
答案:没有
那么如何修改handler表呢?
signal就一直在修改啊
是否有恍然大悟的感觉啊。
案例
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>
#include <wait.h>
#include <vector>
void PrintBlock(const sigset_t &block)
{std::cout<<"block"<<"["<<getpid()<<"]: ";for (int i = 31; i > 0; i--){if (sigismember(&block, i)){std::cout << 1;}else{std::cout << 0;}}std::cout << std::endl;
}void handler(int signo)
{std::cout <<"signo:"<<signo<<" 信号递达"<<std::endl;exit(0);
}
int main()
{signal(2,handler);sigset_t block, oldblock;sigemptyset(&block);// 将二号新号加入sigaddset(&block, 2);//阻塞二号信号int ret = sigprocmask(SIG_SETMASK, &block, &oldblock);if (ret < 0){perror("sigpromask");exit(1);}int cnt = 0;while (true){PrintBlock(block);sleep(3);if(cnt==5){PrintBlock(oldblock);//取消对二号信号的阻塞sigprocmask(SIG_SETMASK, &oldblock, nullptr);}cnt++;}return 0;
}
执行结果
一开始block表中二号信号被阻塞,即使收到了二号信号也不能处理,当修改block表二号没被阻塞时,在执行二号信号相应的处理方法。
信号处理
信号没被处理,被保存起来---->合适的时候
那么什么是合适的时候?
进程从用户态切换会用户态时,检测额pending && block,决定是否用handler表处理信号。
os的运行状态:
1.用户态 ---> 执行用户写的代码
2.内核态 -->执行内核代码
信号自定义捕捉的流程
操作系统是如何运行的?
硬件中断
硬件中断的处理流程
中断向量表在os启动时就填充好了。
时钟中断
进程是由操作系统调度的,那么操作系统谁有谁调度的呢?
有个设备时钟源定期向cpu发送中断,cpu处理中断,执行中断处理历程,而查表查到的终端服务是进程调度。
这样操作系统不就能自主调度了吗
时钟源是外设,将中断传给cpu效率有点低,现在的时钟源都是继承在cpu中。
主频就是控制CPU工作的时钟信号的频率
主频越快,相应单位时间内操作系统执行的中断服务越多,进程调度越频繁,os的性能越高。
进程调度不一定切换进程
软中断
是否能不通过外设来产生中断呢?
可以,比如os支持系统调用,cpu设计了汇编指令(int 0x80 或 syscall),让cpu在内部触发中断逻辑,
这样就可已在软件中触发中断-->再根据中断号,查系统调用表,执行相应的系统调用
系统调用号的本质就是数组下标
死循环
无论是软中断还是硬件中断
os需要什么方法直接,向中断向量表中添加就可以了:os的本质就是一个死循环
void main(void) /* 这⾥确实是void,并没错。 */
{ /* 在startup 程序(head.s)中就是这样假设的。 */
...
/*
* 注意!! 对于任何其它的任务,'pause()'将意味着我们必须等待收到⼀个信号才会返
* 回就绪运⾏态,但任务0(task0)是唯⼀的意外情况(参⻅'schedule()'),因为任
* 务0 在任何空闲时间⾥都会被激活(当没有其它任务在运⾏时),
* 因此对于任务0'pause()'仅意味着我们返回来查看是否有其它任务可以运⾏,如果没
* 有的话我们就回到这⾥,⼀直循环执⾏'pause()'。
*/
for (;;)
pause();
} // end main
---------------------------------------------------------------------------------------------------------------------------------
用户怎么把中断号给os?寄存器(如eax)
os怎么把返回值返回给用户? 也是寄存器
用户和内核之间传递信息用的是寄存器。
系统调用-->是通过软中断完成的
中断号-->系统调用号写入寄存器eax-->软中断-->查表--->执行相应的方法-->将返回值写入寄存器返回给用户
既然执行系统调用需要触发软中断,那我们使用系统调用函数值没有用 int 0x80 或 syscall?
因为linux提供的系统调用接口,不是C语言函数,而是 系统调用号 + 约定的传递参数 ,用于内核和用户间传递信息的 系统调用号和返回值的寄存器 + syscall 或 int 0x80
也就是说GNU glibc 把真正的系统调用封装--->C语言封装版的系统调用
OS是躺在中断处理历程上的代码块。
缺⻚中断?内存碎⽚处理?除零野指针错误?
这些错误都是通过软中断来处理的。
软中断有: 1.陷阱 (int 0x80 或 syscall)
2.异常
理解用户态和内核态
内核页表:整个系统只有一张
用户页表:每个进程都有一张
对于任何进程,不管如何调度,任何进程都只能找到一个os
为什么只有一张内核页表?
因为用户最关心的是系统调用。
用户关心系统调用的地址吗?
不关心,只需要知道系统调用号就可以了。
系统调用是在进程的地址空间中发起的,但其执行是在内核地址空间中完成的。
1.调用任何函数(库中)都是在我们自己进程中的地址空间中进行的
操作系统无论怎么切换进程,进程都只能找到一个操作系统
2.os调用方法的执行是在内核地址空间中执行的
不管是通过哪个进程的地址空间进入内核,都是通过软中断进行操作的。

用户如何进入内核态?
1.时钟/外设中断
2.异常 cpu--->软中断
3.陷阱 系统调用(int 0x80,syscall)
信号的自定义捕捉
1.前三步很好理解,那么为什么要转为用户态来调用处理方法,直接在内核态来处理不好吗?
内核和用户的权限不同,有安全风险;并且用户来处理,如果出了错误用户担责任。
2.信号处理完只能从内核返回,因为处理函数的调用与main()函数之间不存在调用关心(栈区)
3.如何继续执行原来的程序?
cpu中有pc寄存器(pc指针),指向下一条要执行的命令,只需要恢复pc指针的值就可以了。
sigaction
作用检查并修改handler表
sigaction结构
sa_handler :函数指针
sa_mask:自定义屏蔽的信号
信号处理期间,如果处理方法有系统调用,那么就陷入内核态
os不允许信号处理方法嵌套--->实现该方法的方式是将block表相应的信号置为1(阻塞该信号),但信号处理完会自动解除阻塞
什么时候pending表清0?
在调用信号处理之前,因为如果是处理完之后清零,那么就无法区分pending中的1是处理进程时 收到的1,还是处理完时的1
验证阻塞信号
void PrintBlock()
{sigset_t block;sigprocmask(SIG_SETMASK,nullptr,&block);for(int i = 31;i>0;i--){if(sigismember(&block,i))std::cout<<1;elsestd::cout<<0;}std::cout<<std::endl;
}
void handler(int signo)
{std::cout<<"signo: "<<signo<<std::endl;while(true){PrintBlock();sleep(3);}
}int main()
{//signal(2,handler);struct sigaction act,oldact;act.sa_handler = handler;sigaction(2,&act,&oldact);//std::cout<<"执行"<<std::endl;PrintBlock();while(true){pause();}
}
处理完解除对信号的阻塞
void PrintBlock()
{sigset_t block;sigprocmask(SIG_SETMASK,nullptr,&block);for(int i = 31;i>0;i--){if(sigismember(&block,i))std::cout<<1;elsestd::cout<<0;}std::cout<<std::endl;
}
void handler(int signo)
{std::cout<<"signo: "<<signo<<std::endl;// while(true)// {// PrintBlock();// sleep(3);// }PrintBlock();sleep(3);
}int main()
{//signal(2,handler);struct sigaction act,oldact;act.sa_handler = handler;sigaction(2,&act,&oldact);//std::cout<<"执行"<<std::endl;PrintBlock();while(true){pause();PrintBlock();}
}
验证在处理前将pending表清零
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <functional>
#include <sys/types.h>
#include <wait.h>
#include <vector>
void PrintBlock()
{sigset_t block;sigprocmask(SIG_SETMASK, nullptr, &block);std::cout<<"block: ";for (int i = 31; i > 0; i--){if (sigismember(&block, i))std::cout << 1;elsestd::cout << 0;}std::cout << std::endl;
}
void PrintPending()
{sigset_t pending;sigpending(&pending);sigprocmask(SIG_SETMASK, nullptr, &pending);std::cout<<"pending: ";for (int i = 31; i > 0; i--){if (sigismember(&pending, i))std::cout << 1;elsestd::cout << 0;}std::cout << std::endl;
}
void handler(int signo)
{std::cout << "signo: " << signo << std::endl;// while(true)// {// PrintBlock();// sleep(3);// }PrintBlock();PrintPending();sleep(3);
}int main()
{// signal(2,handler);struct sigaction act, oldact;act.sa_handler = handler;sigaction(2, &act, &oldact);// std::cout<<"执行"<<std::endl;PrintBlock();PrintPending();while (true){pause();PrintBlock();PrintPending();}
}
验证sa_mask的作用
void handler(int signo)
{std::cout << "signo: " << signo << std::endl;// while(true)// {// PrintBlock();// sleep(3);// }PrintBlock();//PrintPending();while(true){}//sleep(3);
}int main()
{// signal(2,handler);struct sigaction act, oldact;act.sa_handler = handler;sigset_t mask;sigemptyset(&mask);sigaddset(&mask,2);sigaddset(&mask,3);//把三号信号屏蔽act.sa_mask = mask;//设置屏蔽信号sigaction(2, &act, &oldact);// std::cout<<"执行"<<std::endl;PrintBlock();//PrintPending();while (true){pause();//PrintBlock();//PrintPending();}
}
屏蔽了2号和3号信号
可重入函数
一个函数被两个以上的执行流同时进入--->重入(重复进入)
重入,不出问题--->可重入函数
重入,出问题---> 不可重入函数--->涉及对全局资源的处理
大部分库中的函数都是不可重入函数
重入和不可重入没有好坏之分,只是特性。
案例
因为中断,将node2插入链表,head指向node2,但返回main函数继续执行时,head又指向了node1导致找不到node2,也就造成了内存泄漏。main和信号的处理是两个执行流,进入的都是inset函数。
volatile
volatile是易变关键字
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int flag = 1;
void handler(int signo)
{printf("signo:%d\n",signo);printf("flag -> 0\n");flag = 0;}
int main()
{signal(2,handler);while(flag);printf("quit normal!\n");return 0;
}
没开启编译器优化,会实时更新进程地址空间中flag的值
当把编译器的优化等级开高一些,为什么不退出了呢?
开了优化后,即使进程内存地址空间中的flag改变了,但cpu中的flag不会根据进程地址空间中的flag更新寄存器中的flag,所以一直死循环没有退出 。
volatile flag = 1;//加上volatile关键字
即使优化编译器优化等级开高了,也实时通过进程地址空间中值修改寄存器中的值。
SIGCHLD信号
当子进程退回后----(给父进程发送)--->SIGCHLD信号
waitpid补充
pid为-1时,可以等待任何子进程。
验证子进程退出会给父进程发送SIGCHLD信号
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
void handler(int signo)
{std::cout << "signo: " << signo << std::endl;pid_t ret = waitpid(-1, nullptr, 0);//pid==-1,表示等待任何子进程if (ret > 0){std::cout<<"子进程: "<<ret<<"退出"<<std::endl;}else if (ret < 0){std::cout << "wait error" << std::endl;}sleep(3);
}
int main()
{signal(SIGCHLD, handler);pid_t pid = fork();if (pid == 0){std::cout << "我是子进程: ";std::cout << getpid() << std::endl;exit(0);}std::cout << "我是父进程: " << getpid() << std::endl;while (true);return 0;
}
基于信号对子进程回收
问题1:
如果有n个子进程同时给父进程发送SIGCHLD信号,这是只能记录和处理一个信号;
如果pending记录了一个信号,其他的信号再发过来也不会被记录。
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
void handler(int signo)
{std::cout << "signo: " << signo << std::endl;pid_t ret = waitpid(-1,nullptr,0);if(ret>0){std::cout << "子进程: " << ret << "退出" << std::endl;}else if(ret<0){std::cout<<"wait error"<<std::endl;}
}
int main()
{signal(SIGCHLD, handler);pid_t pid = fork();for (int i = 0; i < 5; i++){pid_t pid = fork();if (pid == 0){std::cout << "我是子进程: ";std::cout << getpid() << std::endl;exit(0);}}while(true);return 0;
}
创建了10个子进程只有7个子进程退出,剩余的子进程发出的信号没有被处理,这些子进程变为了僵尸
解决方法循环回收
void handler(int signo)
{while (true){pid_t ret = waitpid(-1, nullptr, 0);if (ret > 0){std::cout << "子进程: " << ret << "退出" << std::endl;// std::cout << "wait success" << std::endl;}else if (ret < 0){std::cout << "暂时回收完毕" << std::endl;break;}}
}
运行结果:子进程全都被回收
没有僵尸子进程
问题2:
基于问题1,如果10个子进程中,有几个进程迟迟不退出那么,就会阻塞在信号处理那里等待子进程的退出
解决方法
options中有个WNOHANG,如果没有子进程结束则立即返回0
这样处理方法就有阻塞变为了非阻塞,如果有子进程退出则又会在进入循环回收,一次往复,避免了子进程出现僵尸。
pid_t ret = waitpid(-1, nullptr, WNOHANG);
相关文章:

信号保存和信号处理
目录 信号保存中重要的概念 内核中信号的保存 对sigset_t操作的函数 对block,pendding,handler三张表的操作 sigpromask 编辑 sigpending 是否有sighandler函数呢? 案例 信号处理 操作系统是如何运行的? 硬件中断 …...

网站小程序app怎么查有没有备案?
网站小程序app怎么查有没有备案?只需要官方一个网址就可以,工信部备案查询官网地址有且只有一个,百度搜索 "ICP备案查询" 找到官方gov.cn网站即可查询! 注:网站小程序app备案查询,可通过输入单位…...

如何利用宏和VBA来提高文档编辑排版速度?
一个真实的文档修改需求 为什么我会去研究VBA呢?主要原因是今年在一个项目里写了太多的文档。文档中很多操作其实都是机械的、重复的,但是偏偏又很耗时。举个例子,当时有这么一个修改需求,修改文档中所有“输入输出需求表格中”添…...

Kafka - 启用安全通信和认证机制_SSL + SASL
文章目录 官方资料概述制作kakfa证书1.1 openssl 生成CA1.2 生成server端秘钥对以及证书仓库1.3 CA 签名证书1.4 服务端秘钥库导入签名证书以及CA根证书1.5 生成服务端信任库并导入CA根数据1.6 生成客户端信任库并导入CA根证书 2 配置zookeeper SASL认证2.1 编写zk_server_jass…...

c++基础32输入和输出
输入和输出 C风格(使用printf和scanf)输出字符输入字符 C风格(使用cin和cout)输出字符输入字符 注意事项 在C和C中,字符的输入和输出可以通过多种方式实现,包括使用标准输入输出库函数如 printf和 scanf&…...

[C++] 函数详解
前言 今天zty带来的是函数的详解,搞了4个小时,大家给个赞呗,zty还要上学,发作品会少一点 先 赞 后 看 养 成 习 惯 先 赞 后 看 养 成 习 惯 先 赞 后 看 养 成 习 惯 演示用编译器及其…...

AMD CPU下pytorch 多GPU运行卡死和死锁解决
参考链接 https://medium.com/amitparekh/solving-ddp-deadlock-with-multiple-gpus-and-amd-cpus-442186632034 简要说明 AMD的IOMMU和NVIDIA的NCCL不兼容问题导致AMD的IOMMU是BIOS 级组件,它基本上充当将虚拟地址映射到 GPU 上的物理地址的接口,它的全部目的是让 CPU 和 G…...

Swift 开发教程系列 - 第12章:协议与协议扩展
协议(Protocol)是 Swift 的一种重要特性,它定义了实现特定功能的方法、属性或其他要求。通过协议,可以将行为定义从具体实现中分离,使代码更具可读性和扩展性。Swift 的协议支持协议扩展,这一特性允许我们为…...

麒麟V10,arm64,离线安装docker和docker-compose
文章目录 一、下载1.1 docker1.2 docker-compose1.3 docker.service 二、安装三、验证安装成功3.1 docker3.2 docker-compose 需要在离线环境的系统了里面安装docker。目前国产化主推的是麒麟os和鲲鹏的cpu,这块的教程还比较少,记录一下。 # cat /etc/ky…...

NUXT3学习日记二(样式配置、引入组件库、区分在服务端还是在客户端渲染)
上一章已经给大家分享官网下载的nuxt3了,下面正式进入我所要说的内容吧 一、初始化样式 想必大家从我的git下载下来的nuxt3,能看到nuxt.config.ts这个文件了吧。 这里我们有两种css配置方式 1、css:[~/assets/base.scss] 这种方式不能在scss文件中定义…...

FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
基本概念 RTL(Register - Transfer - Level)视图:是一种硬件描述语言的抽象层次,用于描述数字电路中寄存器之间的数据传输和操作。在这个层次上,可以看到电路的基本结构,如寄存器、组合逻辑、多路复用器等…...

Javascript高级—闭包问题
闭包问题 循环中赋值为引用的问题 for (var i 1; i < 5; i) {setTimeout(function timer() {console.log(i)}, i * 1000) }解决方法有3种 第一种,使用立即执行函数方式 for (var i 1; i < 5; i) {(fuction(j){setTimeout(function timer() {console.log…...

C#入门 017 字段,属性,索引器,常量
字段,属性,索引器,常量都表示数据 字段 什么是字段 字段(field)是一种表示与对象或类型(类与结构体)关联的变量字段是类型的成员,又称“成员变量,写在类体里面与对象关联的字段亦称“实例字段,表示某个对…...

磐石云语音助手拦截介绍
呼叫中心用户实际应用场景下最高会有超过30%的和语音助手;无声主要是进入了语音信箱;如:“听到滴声后留言”,”漏话提醒““发送请按1,重录请按2”以及拨打过程中客户主动拒接产生的”您拨打的用户正忙“,”关机“”停…...

JSP执行过程及其与Servlet执行效率的比较
JSP(Java Server Pages)和Servlet都是Java Web开发中常用的技术,它们都用于动态生成Web页面。然而,JSP和Servlet在执行过程和效率上存在一些差异。本文将详细探讨JSP的执行过程,并比较JSP与Servlet的执行效率。 一、J…...

open3d
open3d open3d用于 3D 数据处理的现代库。 简介 Open3D 是一个开源库,支持快速开发处理 3D 数据的软件。Open3D 前端公开了一组精心挑选的 C 和 Python 数据结构和算法。后端经过高度优化,并设置为并行化。Open3D 是从零开始开发的,具有一更…...

Vue中优雅的使用Echarts的三种方式
一、原始方法直接使用 1、安装ECharts: npm install echarts --save 2、创建一个Vue公共组件 EChart.vue: <template><div :style"{width: 100%, height: 300px}" ref"chart"></div> </template><scri…...

SpringBoot配置文件/日志
目录 一,SpringBoot配置文件 1,配置文件的格式: 2,properties 3,yml 1,properties与yml的转换 2,读取配置选哪个中的内容 3,单双引号的差异: 4,配置对象: 5,配置集合/配置map 6,yml的优缺点: 二,验证码: 学习目的: 实现样例: 接口定义: 代码总结: 三,日志: 1,概…...

微服务架构面试内容整理-SpringCloud Netflix与Spring Cloud Alibaba比较
Spring Cloud Netflix 和 Spring Cloud Alibaba 都是用于构建微服务架构的解决方案,但它们在设计理念、组件和使用场景上存在一些差异。以下是它们的比较: 1. 服务注册与发现 ● Spring Cloud Netflix:使用 Eureka 作为服务注册和发现的组件。Eureka 是基于 REST 的,适合服…...

JDBC魔法:连接MySQL数据库与数据操作的秘籍
文章目录 一. JDBC介绍二. 数据库驱动1.DriverManager2.Connection3.PreparedStatement4.ResultSet 三. JDBC连接MySQL1. 加载驱动2. 获得连接3. 关闭连接 四. JDBC实现数据新增五. JDBC实现数据删除 一. JDBC介绍 JDBC(Java Database Connectivity)是Ja…...

深入了解Scratch:引导初学者开启编程之旅
引言 在当今数字化时代,编程已不再是成年人的专利,而是一项逐渐向低年龄段普及的技能。Scratch作为一款面向儿童和青少年的图形化编程语言,以其简单易用且充满趣味性的特点,成为了许多初学者学习编程的首选工具。本文将深入探讨S…...

js复制内容到剪切板
复制内容到剪切板 最近预报一个需求需要点击按钮复制当前到行的内容到剪切板, 所以写了这个工具 export function copyText(text: string, prompt: string | null 已成功复制到剪切板!) {if (navigator.clipboard) {return navigator.clipboard.writeText(text).th…...

代码 RNN原理及手写复现
29、PyTorch RNN的原理及其手写复现_哔哩哔哩_bilibili 笔记连接: https://pan.baidu.com/s/1_Sm7ptEiJtTTq3vQWgOTNg?pwd2rei 提取码: 2rei import torch import torch.nn as nn bs,T2,3 # 批大小,输入序列长度 input_size,hidden_size 2,3 # 输入特征大小&a…...

企业官网的在线客服,如何提高效果?
企业官网的在线客服,如何提高效果? 作者:开源呼叫中心系统 FreeIPCC,github地址:https://github.com/lihaiya/freeipcc 提高企业官网在线客服的效果,是提升客户体验、增强客户满意度和忠诚度的关键。一个…...

「实战应用」如何可视化 DHTMLX Scheduler 中的资源工作量?
DHTMLX Scheduler是一个全面的 UI 组件,用于处理面向业务的 Web 应用程序中复杂的调度和任务管理需求。但是,某些场景可能需要自定义解决方案。例如,如果项目的资源(即劳动力)有限,则需要确保以更高的精度分…...

论文阅读《BEVFormer》
BEVFormer: Learning Bird’s-Eye-View Representation from Multi-Camera Images via Spatiotemporal Transformers 目录 摘要1 介绍2 相关工作2.1 基于Transformer的2D感知 摘要 3D视觉感知任务对于自动驾驶系统至关重要,包括基于多相机图像的3D检测和地图分割。…...

sql专题 之 sql的执行顺序
文章目录 sql的执行顺序sql语句的格式实际的执行顺序:虚拟表 vs 数据集虚拟表 结果集总结嵌套查询在sql查询中的执行顺序 前文我们了解了sql常用的语句,这次我们对于这些语句来个小思索 戳这里→ sql专题 之 常用命令 sql的执行顺序 SQL语句的执行顺序是…...

Vue3 -- 基于Vue3+TS+Vite项目【项目搭建及初始化】
兼容性注意: Vite 需要 Node.js 版本 18+ 或 20+。然而,有些模板需要依赖更高的 Node 版本才能正常运行,当你的包管理器发出警告时,请注意升级你的 Node 版本。【摘抄自vite官网】 这里我用的node版本是 v18.20.2 创建项目: 创建项目我们可以使用npm、yarn、pnpm、bun …...

CTF-RE: TEA系列解密脚本
// // Created by A5rZ on 2024/10/26. //#ifndef WORK_TEA_H #define WORK_TEA_H#endif //WORK_TEA_H#include <cstdint> #include <cstdio>// 定义TEA加密算法的轮次,一般建议为32轮 #define TEA_ROUNDS 32 #define DELTA 0x9e3779b9// TEA加密函数 v…...

信号量和线程池
1.信号量 POSIX信号量,用与同步操作,达到无冲突的访问共享资源目的,POSIX信号量可以用于线程间同步 初始化信号量 #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); sem:指向sem_t类…...