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

【Linux】进程信号全攻略(二)

🌈 个人主页:Zfox_
🔥 系列专栏:Linux

目录

  • 一:🔥 再谈信号的捕捉
    • 🦋 关于信号捕捉的细节部分(sigaction函数)
  • 二:🔥 穿插话题 - 操作系统是怎么运⾏的
    • 🦋 硬件中断
    • 🦋 时钟中断
    • 🦋 OS 死循环
    • 🦋 小结
    • 🦋 如何理解系统调用
  • 三:🔥 缺⻚中断?内存碎⽚处理?除零野指针错误?
  • 四:🔥 如何理解内核态和⽤⼾态
  • 五:🔥 可重入函数
  • 六:🔥 使用信号对全局变量进行操作出现的问题(volatile)
  • 七:🔥 SIGCHLD信号
  • 八:🔥 共勉

一:🔥 再谈信号的捕捉

关于信号捕捉有三种方式:

signal(2, handler);       // 自定义捕捉
signal(2, SIG_IGN);       // 忽略一个信号
signal(2, SIG_DFL);       // 信号的默认处理动作

SIG_IGN 是一个特殊的宏,用于指示系统忽略该信号。

信号可能不会被立即处理,而是在合适的时候处理,那么合适的时候是什么时候呢?

  • 先给结论:从进程的内核态返回到用户态的时候,进行处理。

💦 简单来说,执行自己的代码,访问自己的数据,这就叫做用户态。

💦 当我们进入系统调用时,我们以操作系统的身份来执行时,此时就进入了内核态,操作系统把我们的底层工作做完,做完这些工作后返回到我们的调用处,继续执行下面的代码,但是操作系统,由内核态返回到用户态时,在返回的这个时候信号的检测和处理

这是因为管理信号的数据结构(也就是我们的三张表)都位于进程的控制块(PCB)内,而PCB属于内核数据。因此,信号的检测和处理必须在内核态下进行。

当进程从内核态返回用户态时,内核会检查是否有待处理的信号,并根据信号的处理方式(默认处理、忽略或自定义处理)进行相应的操作。但操作系统不能直接转过去执行用户提供的handler方法,这是出于对安全性的考虑。

在这里插入图片描述

如果信号的处理动作是⽤⼾⾃定义函数,在信号递达时就调⽤这个函数,这称为捕捉信号。

由于信号处理函数的代码是在⽤⼾空间的,处理过程⽐较复杂,举例如下:

  1. ⽤⼾程序注册了 SIGQUIT 信号的处理函数 sighandler
  2. 当前正在执⾏ main 函数, 这时发⽣中断或异常切换到内核态。
  3. 在中断处理完毕后要返回⽤⼾态的 main 函数之前检查到有信号 SIGQUIT 递达。
  4. 内核决定返回⽤⼾态后不是恢复 main 函数的上下⽂继续执⾏,⽽是执⾏ sighandler 函数, sighandler main 函数使⽤不同的堆栈空间,它们之间不存在调⽤和被调⽤的关系,是两个独⽴的控制流程。
  5. sighandler 函数返回后⾃动执⾏特殊的系统调⽤ sigreturn 再次进⼊内核态。
  6. 如果没有新的信号要递达,这次再返回⽤⼾态就是恢复 main 函数的上下⽂继续执⾏了

在这里插入图片描述

🦋 关于信号捕捉的细节部分(sigaction函数)

在这里插入图片描述

  • signum指定要设置或获取处理程序的信号编号。可以指定SIGKILL和SIGSTOP以外的所有信号。
  • act指向 sigaction 结构体的指针,用于指定新的信号处理方式。如果此参数非空,则根据此参数修改信号的处理动作。
  • oldact如果非空,则通过此参数传出该信号原来的处理动作。(如果你想恢复以前的方式,此参数就是保存之前的操作方式)

🦁 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);  // 已废弃,不用关心  
};

🎯 sigaction 函数和 signal 的明显区别:

如果你还想在处理 2 号信号(OS对2号自动屏蔽0),同时,对其它型号也进行屏蔽,你可以设置 sa_mask 变量。

  • 当前如果正在对 2 号信号进行处理,默认 2 号信号会被自动屏蔽,对2号信号处理完成的时候,会自动解除对 2 号信号的屏蔽。为什么?这是因为,操作系统不允许同一个信号被连续处理。
  • 如果 2 号信号处理完毕后,会自动解除对 2 号信号的屏蔽

下面是一段示例:

#include <iostream>
#include <signal.h>
#include <unistd.h>void PrintBlock()
{sigset_t set, oset;sigemptyset(&set);sigemptyset(&oset);sigprocmask(SIG_BLOCK, &set, &oset);std::cout << "block :";for(int signo = 31; signo > 0; signo--){if(sigismember(&oset, signo)){std::cout << 1;}else {std::cout << 0;}}std::cout << std::endl;
}void PrintPending()
{sigset_t pending;::sigpending(&pending);std::cout << "Pending :";for(int signo = 31; signo > 0; signo--){if(sigismember(&pending, signo)){std::cout << 1;}else {std::cout << 0;}}std::cout << std::endl;
}void handler(int signo)
{static int cnt = 0;cnt++;while (true){std::cout << "get a sig" << signo << ", cnt: " << cnt << std::endl;PrintBlock();::sleep(1);break;}
}int main()
{struct sigaction act, oact;act.sa_handler = handler;sigemptyset(&act.sa_mask);sigaddset(&act.sa_mask, 3);sigaddset(&act.sa_mask, 4);sigaddset(&act.sa_mask, 5);sigaddset(&act.sa_mask, 6);sigaddset(&act.sa_mask, 7);::sigaction(2, &act, &oact);while (true){// PrintBlock();PrintPending();::pause();}return 0;
}

🌳 我对3,4,5,6,7号信号也同时做了屏蔽,此时发送2号信号,pending值也是由0置为1的。

在这里插入图片描述

二:🔥 穿插话题 - 操作系统是怎么运⾏的

🦋 硬件中断

• 中断向量表就是操作系统的⼀部分,启动就加载到内存中了
• 通过外部硬件中断,操作系统就不需要对外设进⾏任何周期性的检测或者轮询
• 由外部设备触发的,中断系统运⾏流程,叫做硬件中断
在这里插入图片描述

🦋 时钟中断

☁️ 定义:Linux 时钟中断是指在 Linux 操作系统中,系统定时器周期性地触发中断,这个中断被称为时钟中断。时钟中断源于硬件定时器,通常由计算机的主板芯片或处理器芯片提供,通过定时器计数器来实现定时中断功能。

功能:

  • 维护系统时间每当一个时钟中断发生时,内核会更新系统时间的计数值。这个计数值可以是自世界时间开始的毫秒数,也可以是自系统启动以来的滴答数(tick)。通过定时更新系统时间,系统可以保持时间的准确性,为用户提供可靠的时间信息。

  • 任务调度在多任务操作系统中,内核需要决定哪个进程将获得CPU的控制权。时钟中断提供了一个计时器,每当中断发生时,内核会检查当前运行的进程是否到达了它应该运行的时间片。如果一个进程的时间片用完了,内核就会重新选择下一个要运行的进程,并切换上下文,将控制权交给新的进程。这样保证了系统中进程的公平调度,提高了系统的整体性能。

  • 计算进程执行时间每当一个进程或线程被抢占,切换到另一个进程或线程时,时钟中断记录下了抢占发生的时间。通过记录不同进程和线程的执行时间,可以分析其调度情况,了解系统中进程的运行情况,为性能优化提供依据。

🦋 OS 死循环

💜 如果是这样,操作系统不就可以躺平了吗?对,操作系统⾃⼰不做任何事情,需要什么功能,就向中断向量表⾥⾯添加⽅法即可.操作系统的本质:就是⼀个死循环!

void main(void) /* 这⾥确实是void,并没错。 */
{ /* 在startup 程序(head.s)中就是这样假设的。 */.../** 注意!! 对于任何其它的任务,'pause()'将意味着我们必须等待收到⼀个信号才会返* 回就绪运⾏态,但任务0(task0)是唯⼀的意外情况(参⻅'schedule()'),因为任* 务0 在任何空闲时间⾥都会被激活(当没有其它任务在运⾏时),* 因此对于任务0'pause()'仅意味着我们返回来查看是否有其它任务可以运⾏,如果没* 有的话我们就回到这⾥,⼀直循环执⾏'pause()'。*/for (;;)pause();
} // end main

🦋 小结

操作系统的本质就是一个 死循环 + 时钟中断(不断调度系统的任务): 操作系统中的进程调度依赖于时钟来分配处理器时间。时钟中断定期触发,使操作系统能够检查当前进程的运行状态,并根据需要进行进程切换或调整进程的优先级。时钟通过产生时钟中断来实现进程的时间片管理。每个进程被分配一个固定的时间片来执行,当时钟中断发生时,如果当前进程的时间片已经用完,则操作系统会将其挂起,并选择另一个进程来执行。这种方式确保了每个进程都有机会获得处理器资源,从而提高了系统的整体性能。因此,时钟通过提供稳定的时间基准、实现进程调度、处理中断以及提高系统稳定性与可靠性等方面来推动操作系统的运行。它是操作系统中不可或缺的一部分,对于保证系统的正常运行和任务的有序执行具有重要意义。

🦋 如何理解系统调用

软中断
• 上述外部硬件中断,需要硬件设备触发。
• 有没有可能,因为软件原因,也触发上⾯的逻辑?有!
• 为了让操作系统⽀持进⾏系统调⽤,CPU 也设计了对应的汇编指令 (int 0x80 或者 syscall), 可以让CPU内部触发中断逻辑。
所以:

在这里插入图片描述

用户程序在代码中调用系统调用时,会执行一个特殊的中断指令,如 int 0x80(在x86架构中)或 syscall 指令。在执行中断指令前,将系统调用号放入特定的寄存器中(如eax寄存器)。CPU 暂停当前执行的代码,根据中断的中断号,在中断向量表中找到对应的中断处理程序(如Linux中的 system_call ),并调用它。中断处理程序会检查系统调用号的有效性,并从系统调用表中找到相应的系统调用函数进行调用。
在这里插入图片描述
我们只要找到特定数组下标的方法,就能执行系统调用了。
在这里插入图片描述

问题:
⽤⼾层怎么把系统调⽤号给操作系统? - 寄存器(⽐如EAX)
操作系统怎么把返回值给⽤⼾?- 寄存器或者⽤⼾传⼊的缓冲区地址
系统调⽤的过程,其实就是先int 0x80、syscall陷⼊内核,本质就是触发软中断,CPU就会⾃动执⾏系统调⽤的处理⽅法,⽽这个⽅法会根据系统调⽤号,⾃动查表,执⾏对应的⽅法
系统调⽤号的本质:数组下标

可是为什么我们⽤的系统调⽤,从来没有⻅过什么 int 0x80 或者 syscall 呢?都是直接调⽤上层的函数的啊?
• 那是因为 Linux 的 gnu C 标准库,给我们把⼏乎所有的系统调⽤全部封装了。

在这里插入图片描述在这里插入图片描述

三:🔥 缺⻚中断?内存碎⽚处理?除零野指针错误?

  • 缺⻚中断?内存碎⽚处理?除零野指针错误?这些问题,全部都会被转换成为CPU内部的软中断,然后⾛中断处理例程,完成所有处理。有的是进⾏申请内存,填充⻚表,进⾏映射的。有的是⽤来处理内存碎⽚的,有的是⽤来给⽬标进⾏发送信号,杀掉进程等等。

📌 所以:

  • 操作系统就是躺在中断处理例程上的代码块!
  • CPU内部的软中断,⽐如 int 0x80 或者 syscall,我们叫做 陷阱
  • CPU内部的软中断,⽐如除零/野指针等,我们叫做 异常。(所以,能理解“缺⻚异常”为什么这么叫了吗?)

四:🔥 如何理解内核态和⽤⼾态

在这里插入图片描述
结论:
• 操作系统⽆论怎么切换进程,都能找到同⼀个操作系统!换句话说操作系统系统调⽤⽅法的执⾏,是在进程的地址空间中执⾏的!

  • 内核态: 0-4G 范围的虚拟空间地址都可以操作,尤其是对 3-4G 范围的⾼位虚拟空间地址必须由内核态去操作。

  • 3G - 4G 部分⼤家是共享的(指所有进程的内核态逻辑地址是共享同⼀块内存地址),是内核态的地址空间,这⾥存放在整个内核的代码和所有的内核模块,以及内核所维护的数据。
    在这里插入图片描述

  • 关于特权级别,涉及到段,段描述符,段选择⼦,DPL,CPL,RPL等概念, ⽽现在芯⽚为了保证兼容性,已经⾮常复杂了,进⽽导致OS也必须得照顾它的复杂性,这块我们不做深究了。

  • ⽤⼾态就是执⾏⽤⼾ [0,3] GB 时所处的状态

  • 内核态就是执⾏内核 [3,4] GB 时所处的状态

  • 区分就是按照CPU内的CPL决定,CPL的全称是Current Privilege Level,即当前特权级别。

  • ⼀般执⾏ int 0x80 或者 syscall 软中断,CPL会在校验之后⾃动变更

  • 这样会不会不安全??

五:🔥 可重入函数

在这里插入图片描述

  • main 函数调用 insert 函数向一个链表 head 中插入节点 node1, 插入操作分为两步,刚做完第一步的 时候, 因为硬件中断使进程切换到内核, 再次回用户态之前检查到有信号待处理, 于是切换 到 sighandler 函数, sighandler 也调用 insert 函数向同一个链表 head 中插入节点 node2 , 插入操作的两步都做完之后从 sighandler 返回内核态, 再次回到用户态就从 main 函数调用的 insert 函数中继续往下执行, 先前做第一步之后被打断, 现在继续做完第二步。结果是 main 函数和 sighandler 先后向链表中插入两个节点, 而最后只有一个节点真正插入链表中了。
  • 像上例这样, insert 函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数, 这称为重入, insert 函数访问一个全局链表, 有可能因为重入而造成错乱, 像这样的函数称为不可重入函数, 反之, 如果一个函数只访问自己的局部变量或参数, 则称为可重入 (Reentrant) 函数。想一下, 为什么两个不同的控制流程调用同一个函数, 访问它的同一个局部变量或参数就不会造成错乱?
    \qquad

如果一个函数符合以下条件之一则是不可重入的:(大部分函数是不可被重入的,可重入或者不可重入,描述的是函数的特征)

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

六:🔥 使用信号对全局变量进行操作出现的问题(volatile)

int gflag = 0;void changedata(int signo)
{std::cout << "get a signo:" << signo << ", change gflag 0->1" << std::endl;gflag = 1;
}int main() // 没有任何代码对gflag进行修改!!!
{signal(2, changedata);while(!gflag); // while不要其他代码std::cout << "process quit normal" << std::endl;
}

我们捕捉了2号信号,当我们执行了2号信号后,全局变量 gflag 就会被更改为1,那么 main 函数中的 while 就会停止执行,因为 cpu 在执行 while 循环的时候,实时的从内存中取 gflag 来进行比较,但在这里我们对编译进行优化,这会让 cpu 保存之前在内存中取的 gflag 的值,只在内存中取最开始的一次值, 其余都在寄存器的缓存中读取,这就会导致 gflag 的变化无法被在 while 中实时更新,导致 while 循环无法结束:g++ -o test test.cc -O1(O1,是基础优化)
在这里插入图片描述
如果想让 gflag 在此优化下生效,就要使用 volatile(volatile关键字可以确保变量的可见性(即确保变量每次访问时都直接从内存中读取)关键字调整后,程序成功退出:

volatile int gflag = 0;

在这里插入图片描述

七:🔥 SIGCHLD信号

子进程退出时,不是静悄悄的退出的,会给父进程发送信号–SIGCHLD信号。
下面是一段示例:

#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>void notice(int signo)
{std::cout << "get a signal: " << signo << " pid: " << getpid() << std::endl;while (true){pid_t rid = waitpid(-1, nullptr, WNOHANG); // 阻塞啦!!--> 非阻塞方式if (rid > 0){std::cout << "wait child success, rid: " << rid << std::endl;}else if (rid < 0){std::cout << "wait child success done " << std::endl;break;}else{std::cout << "wait child success done " << std::endl;break;}}
}void DoOtherThing()
{std::cout << "DoOtherThing~" << std::endl;
}int main()
{signal(SIGCHLD, notice);for (int i = 0; i < 10; i++){pid_t id = fork();if (id == 0){std::cout << "I am child process, pid: " << getpid() << std::endl;sleep(3);exit(1);}}// fatherwhile (true){DoOtherThing();sleep(1);}return 0;
}

这段代码创建了多个子进程,并在子进程结束时通过 SIGCHLD 信号进行处理。

  • SIGCHLD 信号被捕获时,notice 函数会被调用。这个函数会进入一个无限循环,尝试使用 waitpid 以非阻塞方式 (WNOHANG) 等待任何已终止的子进程。这是合理的,因为它允许父进程在子进程终止时及时回收资源,同时不阻塞父进程的其他操作。

八:🔥 共勉

以上就是我对 【Linux】进程信号全攻略(二) 的理解,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉
在这里插入图片描述

相关文章:

【Linux】进程信号全攻略(二)

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; 再谈信号的捕捉 &#x1f98b; 关于信号捕捉的细节部分&#xff08;sigaction函数&#xff09; 二&#xff1a;&#x1f525; 穿插话题 - 操作系统是怎么运…...

redis用法(二)

文章目录 02-redis数据类型篇生产环境下的redis实况图 1.全局命令redis数据存储格式set设置k-v查看当前redis的key的数量危险命令&#xff0c;新手请在于超老师陪同下执行为什么危险&#xff1f;如何正确搜索redis的key 查看库下有多少个key查询redis库信息切换redis库查看key是…...

Python-利用os,tkinter库编写一个伪恶意程序文件(Pro版)

前言&#xff1a;上一期我们简单学习了如何编写一个多次弹窗警告用户的exe伪恶意文件。我们知道了把Python初始文件编译为exe文件后&#xff0c;程序在没有Python环境的情况下也能正常运行。我们上次编写的程序仅仅只是伪造系统正在执行关机命令前的倒计时的假象&#xff0c;实…...

Oracle视频基础1.4.4练习

1.4.4 [dbs] 删干净上次创建的bbk ll rm -f *dbf ll rm -f spfilebbk.ora clear ll创建bbk的pfile&#xff0c;准备对应的目录 ll strings spfilewilson.ora | more strings spfilewilson.ora > initbbk.ora :%s/wilson/bbk :%s/*\.//g :wq ll vi initbbk.ora####### 创…...

GOF的C++软件设计模式的分类和模式名称

“GOF” 指的是 “Gang of Four”&#xff0c;即“四人帮”&#xff0c;他们是指 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides。这四位作者在其著作《Design Patterns: Elements of Reusable Object-Oriented Software》中定义了23种设计模式&#xff0c;这些…...

有向图的完全可达性(有向图搜索全路径的问题) C#DFs

在考察输入输出方面我觉得是道难题了 第一次遇见邻接表的数据结构该怎么声明 卡码网105 在力扣没找见完全相同的题 感觉需要多练习多复习这种类型的题 105. 有向图的完全可达性 题目描述 给定一个有向图&#xff0c;包含 N 个节点&#xff0c;节点编号分别为 1&…...

前端开发实现自定义勾选/自定义样式,可复选,可取消勾选

基于后端返回数组实现多选、复选 以下代码基于vue2&#xff0c;如果有需要React/Vue3或者其他框架代码的&#xff0c;可以通过国内直连GPT4o进行代码转换&#xff0c;转换正确率99% 前端代码如下(直接拷贝到你的vue代码即可)&#xff1a; <!-- CustomCheckboxList.vue --&g…...

鸿蒙-promptAction.showToast基于PC屏幕底部提示

PC端app缩小&#xff0c;右击出菜单后&#xff0c;点菜单项 菜单关闭&#xff0c;并弹promptAction.showToast提示&#xff0c;但提示是基于PC底部弹提示的&#xff0c;需要的是基于app底部弹提示 原因是UIContext是右击菜单的UIContext&#xff0c;需要拿到菜单下面UI的UICont…...

Vert.x,应用监控 - 全链路跟踪,基于Zipkin

关于Zipkin Zipkin是一款开源的分布式实时数据追踪系统(Distributed Tracking System)&#xff0c;能够收集服务间调用的时序数据&#xff0c;提供调用链路的追踪。Zipkin每一个调用链路通过一个trace id来串联起来&#xff0c;通过trace id&#xff0c;就能够直接定位到这次调…...

Rust常用数据结构教程 序列

文章目录 一、Vec1.Vec与堆栈2.什么时候需要Vec3.get()方法4.与枚举的结合 二、VecDeque1.什么情况适合VecDeque2.VecDeque的方法 三、LinkedList1.什么时候用LinkedList 参考 一、Vec 可变数组(vector)数组存储在heap上,在运行时(runtime)可以增加或减少数组 长度 有人把Ve…...

智慧城市路面垃圾识别系统产品介绍方案

方案介绍 智慧城市中的路面垃圾识别算法通常基于深度学习框架&#xff0c;这些算法因其在速度和精度上的优势而被广泛采用。这些模型能够通过训练识别多种类型的垃圾&#xff0c;包括塑料袋、纸屑、玻璃瓶等。系统通过训练深度学习模型&#xff0c;使其能够识别并定位多种类型…...

网络安全:构建坚固的数字堡垒

网络安全&#xff1a;构建坚固的数字堡垒 在当今数字化时代&#xff0c;网络安全已经成为企业和个人不可忽视的重要议题。随着互联网的普及和信息技术的快速发展&#xff0c;网络攻击、数据泄露和隐私侵犯等问题日益严重&#xff0c;给企业和个人带来了巨大的风险和损失。本文…...

LeetCode题练习与总结:打乱数组--384

一、题目描述 给你一个整数数组 nums &#xff0c;设计算法来打乱一个没有重复元素的数组。打乱后&#xff0c;数组的所有排列应该是 等可能 的。 实现 Solution class: Solution(int[] nums) 使用整数数组 nums 初始化对象int[] reset() 重设数组到它的初始状态并返回int[]…...

科技改变生活:最新智能开关、调光器及插座产品亮相

根据QYResearch调研团队的最新力作《欧洲开关、调光器和插座市场报告2023-2029》显示&#xff0c;预计到2029年&#xff0c;欧洲开关、调光器和插座市场的规模将攀升至57.8亿美元&#xff0c;并且在接下来的几年里&#xff0c;将以4.2%的复合年增长率&#xff08;CAGR&#xff…...

传统RAG流程;密集检索器,稀疏检索器:中文的M3E

目录 传统RAG流程 相似性搜索中:神经网络的密集检索器,稀疏检索器 密集检索器 BGE系列模型 text-embedding-ada-002模型 M3E模型 稀疏检索器 示例一:基于TF-IDF的稀疏检索器 示例二:基于BM25的稀疏检索器 稀疏检索器的特点与优势 传统RAG流程 相似性搜索中:神经…...

基于统计方法的语言模型

基于统计方法的语言模型 基于统计方法的语言模型主要是指利用统计学原理和方法来构建的语言模型&#xff0c;这类模型通过分析和学习大量语料库中的语言数据&#xff0c;来预测词、短语或句子出现的概率。 N-gram模型&#xff1a;这是最基础的统计语言模型之一&#xff0c;它基…...

Flux comfyui 部署笔记,整合包下载

目录 comfyui启动: 1、下载 Flux 模型 2、Flux 库位置 工作流示例: Flux学习资料免费分享 comfyui启动: # 配置下载模型走镜像站 export HF_ENDPOINT="https://hf-mirror.com" python3 main.py --listen 0.0.0.0 --port 8188 vscode 点击 port 映射到本地,…...

高性能分布式缓存Redis-数据管理与性能提升之道

一、持久化原理 Redis是内存数据库&#xff0c;数据都是存储在内存中&#xff0c;为了避免进程退出导致数据的永久丢失&#xff0c;需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘&#xff1b;当下次Redis重启时&#xff0c;利用持久化文件实现数据恢复。除此…...

BO-CNN-LSTM回归预测 | MATLAB实现BO-CNN-LSTM贝叶斯优化卷积神经网络-长短期记忆网络多输入单输出回归预测

BO-CNN-LSTM回归预测 | MATLAB实现BO-CNN-LSTM贝叶斯优化卷积神经网络-长短期记忆网络多输入单输出回归预测 目录 BO-CNN-LSTM回归预测 | MATLAB实现BO-CNN-LSTM贝叶斯优化卷积神经网络-长短期记忆网络多输入单输出回归预测效果一览基本介绍模型搭建程序设计参考资料 效果一览 …...

DataWind将字符串数组拆出多行的方法

摘要&#xff1a; 可视化建模中先将字符串split为array再用explode(array)即可 可视化建模 进入“可视化建模”页面 1.1 新建任务 如果团队内没有可视化建模任务。请点击“新建任务”&#xff0c;输入名称并确定。 1.2 建立数据连接 在左边栏中选择“数据连接”&#xff0c…...

try...catch 和then...catch的异同点分析

try…catch 和 then…catch 的异同点分析 在现代 JavaScript 编程中&#xff0c;异常处理和 Promise 的处理是非常常见的两种方式。try...catch 语句主要用于同步代码的异常处理&#xff0c;而 .then().catch() 是 Promise 中的异步处理方法。 1. 基础概念 1.1 try…catch …...

Mit6.S081-实验环境搭建

Mit6.S081-实验环境搭建 注&#xff1a;大家每次做一些操作的时候觉得不太保险就先把虚拟机克隆一份 前言 qemu&#xff08;quick emulator&#xff09;&#xff1a;这是一个模拟硬件环境的软件&#xff0c;利用它可以运行我们编译好的操作系统。 准备一个Linux系统&#xf…...

以太网交换安全:MAC地址漂移

一、什么是MAC地址漂移&#xff1f; MAC地址漂移是指设备上一个VLAN内有两个端口学习到同一个MAC地址&#xff0c;后学习到的MAC地址表项覆盖原MAC地址表项的现象。 MAC地址漂移的定义与现象 基本定义&#xff1a;MAC地址漂移发生在一个VLAN内的两个不同端口学习到相同的MAC地…...

STM32实现串口接收不定长数据

原理 STM32实现串口接收不定长数据&#xff0c;主要靠的就是串口空闲&#xff08;idle&#xff09;中断,此中断的触发条件与接收的字节数无关&#xff0c;只有当Rx引脚无后续数据进入时&#xff08;串口空闲时&#xff09;&#xff0c;认为这时候代表一个数据包接收完成了&…...

AAA 数据库事务隔离级别及死锁

目录 一、事务的四大特性&#xff08;ACID&#xff09; 1. 原子性(atomicity)&#xff1a; 2. 一致性(consistency)&#xff1a; 3. 隔离性(isolation)&#xff1a; 4. 持久性(durability)&#xff1a; 二、死锁的产生及解决方法 三、事务的四种隔离级别 0 .封锁协议 …...

外接数据库给streamlit等web APP带来的变化

之前我采用sreamlit制作了一个调查问卷的APP&#xff0c; 又使用MongoDB作为外部数据存储&#xff0c;隐约觉得外部数据库对于web APP具有多方面的意义&#xff0c;代表了web APP发展的趋势之一&#xff0c;似乎是作为对这种趋势的响应&#xff0c;streamlit官方近期开发了st.c…...

Gitpod: 我们正在离开 Kubernetes

原文&#xff1a;Christian Weichel - 2024.10.31 Kubernetes 似乎是构建远程、标准化和自动化开发环境的显而易见选择。我们也曾这样认为&#xff0c;并且花费了六年时间&#xff0c;致力于打造最受欢迎的云开发环境平台&#xff0c;并达到了互联网级的规模。我们的用户数量达…...

1.每日SQL----2024/11/7

题目&#xff1a; 计算用户次日留存率,即用户第二天继续登录的概率 表&#xff1a; iddevice_iddate121382024-05-03232142024-05-09332142024-06-15465432024-08-13523152024-08-13623152024-08-14723152024-08-15832142024-05-09932142024-08-151065432024-08-131123152024-…...

普通一本大二学生,软件工程,想考研985,想知道哪个大学的软件工程好,又不至于完全考不起的?

竞争难度适中&#xff1a;相较于顶尖985院校&#xff0c;重庆大学作为实力派985高校&#xff0c;其竞争烈度较为温和&#xff0c;考研难度适中偏易&#xff0c;为追求高性价比深造路径的考生提供了理想之选。 考试难度友好&#xff1a;重庆地区考研评分标准相对宽松&#xff0…...

「QT」几何数据类 之 QMatrix4x4 4x4矩阵类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…...