【Linux】信号保存{sigset_t/sigpending/sigprocmask/bash脚本/代码演示}

文章目录

  • 1.信号相关常见概念
  • 2.管理信号的数据结构
  • 3.初识sigset_t
  • 4.信号集操作函数
    • 4.1sigpending
    • 4.2sigprocmask
    • 4.2代码测试
      • 1.测试1
      • 2.测试2
      • 3.测试3
    • 4.3bash 脚本文件


在这里插入图片描述

1.信号相关常见概念

信号相关动作:产生 发送 接收 阻塞 递达(处理)
实际执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达之间的状态 称为信号未决(Pending)
进程可以选择阻塞 (Block )某个信号
信号产生后未被递达前 或 被阻塞的信号 将保持在未决状态 直到进程解除对此信号的阻塞 才执行递达的动作

阻塞信号和忽略信号的区别

阻塞和忽略是不同的 只要信号被阻塞就不会递达 而忽略是在递达之后可选的一种处理动作
忽略: 对信号已经进行了处理,处理方式是不做处理
阻塞:压根就没有对信号进行处理。

2.管理信号的数据结构

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

  1. 在进程PCB中,信号的pending位图、block位图和handler函数指针数组是用于管理信号处理的数据结构。
  2. 每个信号都有两个标志位分别表示阻塞(block)和未决(pending) 以及一个函数指针数组表示处理动作
  3. 信号产生未被递达时 内核在进程控制块中设置该信号的未决标志 直到信号递达才清除该标志
  4. a. 上图SIGHUP信号未阻塞也未产生过 当它递达时执行默认处理动作
    b. SIGINT信号产生了 但正在被阻塞 暂时不能递达 虽然它的处理动作是IGN(忽略) 但在没有解除阻塞之前 这个信号是不能进行处理即去忽略的 【在解除阻塞前进程仍有机会改变处理动作】
    c. SIGQUIT信号未产生过 一旦产生SIGQUIT信号将被阻塞 它的处理动作是用户自定义函sighandler

如果在进程解除对某信号的阻塞之前 这种信号产生过多次 将如何处理?

POSIX.1允许系统递送该信号一次或多次。
Linux是这样实现的:常规信号在递达之前产生多次只计一次 而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信号。

解读相关数据结构

在这里插入图片描述

在Linux下,PCB(进程控制块)的pending位图与信号的处理紧密相关。pending位图主要表示已经收到但是还没有被递达的信号。换句话说,当一个进程接收到一个信号,但这个信号尚未被进程处理(例如,因为进程当前正在执行某个不允许被中断的操作,或者信号的处理函数尚未被执行),那么这个信号的状态就会被记录在pending位图中。

pending位图的作用在于跟踪哪些信号已经到达进程但尚未被处理。这允许操作系统在适当的时机递达这些信号,比如当进程处于可以安全处理信号的状态时。通过这种方式,pending位图确保了信号的可靠传递和处理,防止了信号的丢失或重复处理。

在更深入地理解pending位图时,还需要考虑其他与信号相关的PCB属性,如block位图(表示哪些信号不应该被递达,直到解除阻塞)和信号屏蔽字(handle函数指针数组,用于定义每个信号的处理方式)。这些属性与pending位图一起,共同构成了Linux中进程信号处理的复杂而精细的机制。

总的来说,pending位图是Linux进程控制块中用于跟踪和管理已接收但尚未处理信号的重要数据结构,它确保了信号的可靠性和高效性。
Pending信号集:每个进程都有一个pending位图,用于记录当前已经被该进程接收但尚未处理(递达)的信号(未决信号)。当一个信号被接收时,对应的位会被设置为1,表示该信号已产生处于未决状态,直到信号递达(处理)才清除该标志。进程可以通过检查pending位图来确定是否有已产生未处理的信号。在Linux中,可以使用sigpending函数来获取当前进程的pending位图。

Block信号屏蔽字:每个进程都有一个block位图,用于指定当前被阻塞的信号。当一个信号被阻塞时,对应的位会被设置为1,表示该信号被阻塞,暂时不会被递达。进程可以通过设置block位图来控制哪些信号被阻塞,以避免进程在关键时刻被中断。在Linux中,可以使用sigprocmask函数来设置和获取当前进程的block位图。

Handler函数指针数组:每个进程都有一个handler函数指针数组,用于管理信号处理函数。该数组的索引对应于信号的编号,数组的元素是函数指针,指向相应信号的处理函数。当进程接收到一个信号时,会根据信号的编号在handler函数指针数组中查找对应的处理函数,并调用该函数来处理信号。在Linux中,可以使用signal和sigaction函数来设置和获取信号处理函数。

之前我们的文章中signal函数自定义处理信号的原理:将信号处理函数的指针填入到handler数组对应信号编号的位置。
pending位图、block位图和handler函数指针数组是针对每个进程而言的,每个进程都有自己独立的位图和数组。这样可以实现不同进程对信号的独立管理和处理。

3.初识sigset_t

在这里插入图片描述

  1. 从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。
  2. 未决和阻塞标志可以用相同的数据类型sigset_t来表示 sigset_t称为信号集 这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。
  3. 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。

什么是sigset_t?

sigset_t 是 Linux 系统中用于表示信号集的数据类型。信号集是一组信号的集合,这些信号可以是未决信号(即已经发送但尚未处理的信号)或阻塞信号(即当前被阻塞不处理的信号)。sigset_t 可以看作是一个由二进制位组成的大整数,每一位对应一个信号,某一位为 1 表示信号集中包含该信号,为 0 则表示不包含。

在编程中,可以使用多种函数来操作 sigset_t 类型的信号集。例如,sigemptyset() 函数用于创建一个空的信号集,sigaddset() 函数用于向信号集中添加信号,sigdelset() 函数用于从信号集中删除信号。

在多线程编程中,pthread_sigmask() 函数特别有用,它允许你在主线程中控制信号掩码。这个函数接受三个参数:一个操作方式(SIG_BLOCK、SIG_UNBLOCK 或 SIG_SETMASK),一个指向信号集的指针(表示要设置或修改的信号集),以及一个可选的指向旧信号集的指针(用于保存之前的信号集状态)。

需要注意的是,直接修改 sigset_t 类型的内部数据可能并不安全或有效,通常建议使用专门的函数来操作信号集。同时,处理信号和信号集时应当小心谨慎,以避免潜在的竞态条件或错误。

总的来说,sigset_t 是 Linux 系统中用于处理信号的重要数据类型,它提供了一种方便的方式来表示和操作信号集。通过相关的函数,你可以轻松地创建、修改和查询信号集,以满足不同的编程需求。

计算机常识

  1. 语言会提供.h,.hpp 和自定义类型
  2. OS也会提供.h,和 OS自定义的类型(为了让用户能够用接口,接口的参数又不能是语言里的类型,或者语言里没有这种类型)
  3. 语言的一些库函数如读写函数封装了系统接口,那么读写函数的头文件中有可能就包含了系统的头文件

理解sigset_t

sigset_t:user是可以直接使用该类型 与 用内置类型 && 自定义类型 没有任何差别

4.信号集操作函数

sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的

sigset_t:不允许用户自己进行位操作,OS提供了对应的操作位图的方法

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
  1. 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。
  2. 函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置1,表示该信号集的有效信号包括系统支持的所有信号。
  3. 在使用sigset_ t类型的变量之前,要调用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。
  4. 初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。
  5. sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。
  6. 这四个函数都是成功返回0,出错返回-1。

sigset_t:一定需要对应的系统接口来完成对应的功能,其中系统接口需要的参数,可能就包含了sigset_t定义的变量或者对象 接下来的4.1/4.2即为系统接口

4.1sigpending

OS通过这个接口将set给用户
在这里插入图片描述
sigpending 是一个在 Unix 和 Linux 系统中用于获取当前进程挂起信号集的函数。挂起信号集是指那些已经发送到进程,但尚未被处理的信号。

函数的原型如下:

c
int sigpending(sigset_t *set);
参数说明:

set:指向一个 sigset_t 类型的变量,函数会将当前进程的挂起信号集存储在这个变量中。
返回值:

如果成功,则返回 0。
如果失败,则返回 -1,并设置 errno 以指示错误。
sigpending 函数允许进程查询哪些信号当前处于挂起状态,即哪些信号已经发送给进程但尚未被处理。这对于进程来说是非常有用的信息,因为它可以根据这些信息来决定如何响应这些挂起信号,或者进行其他相关操作。

注意,sigpending 函数返回的是挂起信号集,而不是当前进程的信号屏蔽字。挂起信号集是那些已经发送但尚未处理的信号,而信号屏蔽字则决定了哪些信号当前被进程阻塞。因此,即使某个信号在挂起信号集中,如果它也在信号屏蔽字中,那么进程也不会立即响应它。

使用 sigpending 时,通常需要与 sigprocmask 等函数结合使用,以便进程能够更全面地控制和处理信号。

4.2sigprocmask

在这里插入图片描述
sigprocmask 是一个在 Unix 和 Linux 系统中用于检查和/或更改当前进程的信号屏蔽字的函数。信号屏蔽字是一个位掩码,用于控制哪些信号当前应该被进程阻塞(即忽略)。

函数的原型如下:

c
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数说明:

how:指定如何修改当前的信号屏蔽字。它可以是以下三个值之一:

SIG_BLOCK:将 set 所指向的信号集中的信号添加到当前的信号屏蔽字中。mask |= set
SIG_UNBLOCK:从当前的信号屏蔽字中移除 set 所指向的信号集中的信号。mask = mask &~set
SIG_SETMASK:将当前的信号屏蔽字设置为 set 所指向的信号集。mask = set
set:指向一个 sigset_t 类型的变量,该变量包含了一组信号,这些信号将根据 how 参数的值被添加到、从或从当前信号屏蔽字中移除。

oldset:如果此参数不是 NULL,则函数会将调用前的信号屏蔽字存储在 oldset 所指向的 sigset_t 变量中。

返回值:

如果成功,则返回 0。
如果失败,则返回 -1,并设置 errno 以指示错误。
sigprocmask 函数允许进程精细地控制哪些信号应被阻塞。这对于实现多线程程序中的同步机制,或者在执行某些不能被信号中断的临界区代码时特别有用。通过阻塞某些信号,进程可以确保在关键代码段执行期间不会被这些信号中断。

注意,sigprocmask 修改的是调用进程的信号屏蔽字,因此它只对调用它的进程有效。此外,阻塞的信号仍然可以被进程接收,只是它们不会中断进程的执行,直到信号屏蔽字被修改以允许这些信号为止。

4.2代码测试

1.测试1

如果我们对所有的信号都进行了自定义捕捉 我们是不是就写了一个不会被异常或者用户杀掉的进程? 并不是,OS的设计者也考虑了
在这里插入图片描述

在这里插入图片描述在这里插入图片描述
9号信号不可被捕获 ⇒ 管理员信号

2.测试2

如果我们将2号信号block,并且不断的获取并打印当前进程的pending信号集,如果我们突然发送一个2号信号,我们就应该肉眼看到pending信号集中,有一个比特位0->1

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>static void showPending(sigset_t &pending)
{for (int sig = 31; sig >=1; sig--){if (sigismember(&pending, sig))std::cout << "1";elsestd::cout << "0";}std::cout << std::endl;
}int main()
{// 1. 定义信号集对象sigset_t set, oldset, pending;// 2. 初始化sigemptyset(&set);sigemptyset(&oldset);sigemptyset(&pending);// 3. 添加要进行屏蔽的信号sigaddset(&set, 2 /*SIGINT*/);// 4. 将set添加到当前的信号屏蔽字中(内核的进程内部)//[默认情况进程不会对任何信号进行block]int n = sigprocmask(SIG_BLOCK, &set, &oldset);assert(n == 0);(void)n;std::cout << "block 2 signal success...., pid: " << getpid() << std::endl;// 5. 重复打印当前进程的pending信号集while (true){// 5.1 获取当前进程的pending信号集sigpending(&pending);// 5.2 显示pending信号集中信号状态showPending(pending);sleep(1);}return 0;
}

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

  • 如果解除2号信号的阻塞 会发生什么?
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>static void handler(int signum)
{std::cout << "捕获信号:" << signum << std::endl;// exit(1); 不终止进程
}static void showPending(sigset_t &pending)
{for (int sig = 1; sig <= 31; sig++){if (sigismember(&pending, sig))std::cout << "1";elsestd::cout << "0";}std::cout << std::endl;
}int main()
{// 0. 测试 捕捉2号信号 不让其执行默认终止动作signal(2, handler);// 1. 定义信号集对象sigset_t set, oldset;sigset_t pending;// 2. 初始化sigemptyset(&set);sigemptyset(&oldset);sigemptyset(&pending);// 3. 添加要进行屏蔽的信号sigaddset(&set, 2 /*SIGINT*/);// 4. 设置set到内核中对应的进程内部[默认情况进程不会对任何信号进行block]int n = sigprocmask(SIG_BLOCK, &set, &oldset);assert(n == 0);(void)n;std::cout << "block 2 号信号成功...., pid: " << getpid() << std::endl;// 5. 重复打印当前进程的pending信号集int count = 0;while (true){// 5.1 获取当前进程的pending信号集sigpending(&pending);// 5.2 显示pending信号集中的没有被递达的信号showPending(pending);sleep(1);count++;if (count == 20){// 默认情况下 解除2号信号的阻塞 确实会进行递达// 2号信号的默认处理动作是终止进程 需要对2号信号进行捕捉std::cout << "Unblock signal 2" << std::endl;int n = sigprocmask(SIG_SETMASK, &oldset, nullptr);assert(n == 0);(void)n;}}return 0;
}

在这里插入图片描述

在这里插入图片描述

上面0和1的顺序是可以通过输出格式控制的逆序遍历 ⇒ 正向输出

我们可以获取sigpending 貌似没有一一个接口用来设置pending位图(所有的信号发送方式,都是修改pending位图的过程)

3.测试3

如果我们对所有的信号都进行block 我们是不是就写了一个不会被异常或者用户杀掉的进程

监测指令

i=1; id=$(pidof mysignal);\
> while [ $i -le 31 ]; do echo "i: $i, id: $id";\
> let i++; sleep 1; donei=1; id=$(pidof mysignal);\
> while [ $i -le 31 ]; do kill -$i $id; \
> echo "sending signal $i";\
> let i++; sleep 1; done

在这里插入图片描述在这里插入图片描述
9号信号也不可以被屏蔽/阻塞

SIGKILL(9)信号 和 SIGSTOP(19)信号 不能被捕捉,也不能被阻塞。20号信号默认动作是忽略(猜测)

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

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>static void showPending(sigset_t &pending)
{for (int sig = 31; sig >= 1; sig--){if (sigismember(&pending, sig))std::cout << "1";elsestd::cout << "0";}std::cout << std::endl;
}static void blockSig(int sig)
{sigset_t set;sigemptyset(&set);sigaddset(&set, sig);int n = sigprocmask(SIG_BLOCK, &set, nullptr);assert(n == 0);(void)n;
}int main()
{for(int sig = 1; sig <= 31; sig++){blockSig(sig);}sigset_t pending;while(true){sigpending(&pending);showPending(pending);sleep(1);}return 0;
}

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

4.3bash 脚本文件

#!/bin/bashi=1
id=$(pidof mysignal)
while [ $i -le 31 ]
doif [ $i -eq 9 ];thenlet i++continuefiif [ $i -eq 19 ];thenlet i++continuefikill -$i $idecho "kill -$i $id"let i++sleep 1
done

#!/bin/bash
这一行称为 shebang 或 hashbang。它告诉操作系统该脚本应该使用哪个解释器来执行。在这个例子中,它指定了使用 /bin/bash,也就是 Bourne Again SHell 的路径,这是许多 Linux 和 Unix 系统中的默认 shell。当你尝试运行这个脚本时(例如,通过输入 ./scriptname.sh),操作系统会查看脚本的第一行,并使用 /bin/bash 来解释和执行脚本的内容。
2. if … then … fi

这是 Bash 中的条件语句结构。它用于根据某个条件是否满足来执行不同的代码块。

  • if [ 条件 ]:检查后面的条件是否满足。如果满足,则执行 then 后面的代码块。
  • then:表示如果前面的条件满足,则执行接下来的代码块。
  • fi:表示 if 语句的结束。
    在你的脚本中,有两个 if 语句,分别检查 $i 是否等于 9 或 19。如果等于这两个值,脚本会跳过发送信号的部分,并直接继续到下一个循环迭代。
  1. then

如上所述,then 关键字用于 if 语句中,表示如果前面的条件满足,则执行 then 后面的代码块。

为了更清楚地理解,让我们看一个简化的例子:

bash
#!/bin/bash  number=5  if [ $number -eq 5 ]; then  echo "The number is 5."  
fi

在这个例子中,脚本会检查变量 number 是否等于 5。如果是,它会输出 “The number is 5.”。fi 表示 if 语句的结束。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2871082.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

0基础 三个月掌握C语言(11)

字符函数和字符串函数 为了方便操作字符和字符串 C语言标准库中提供了一系列库函数 接下来我们学习一下这些函数 字符分类函数 C语言提供了一系列用于字符分类的函数&#xff0c;这些函数定义在ctype.h头文件中。这些函数通常用于检查字符是否属于特定的类别&#xff0c;例如…

html--宠物

文章目录 htmljscss html <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>CodePen - Spaceworm</title><script> window.requestAnimFrame (function() {return (window.requestAnimat…

粤嵌6818开发板触摸屏应用

一、触摸屏应用 1.触摸屏设备的名字 在Linux下&#xff0c;一切皆文件&#xff0c;触摸屏也是一个文件。 触摸屏设备的名字&#xff1a;/dev/input/event0 2.触摸屏的两个专业术语 事件 ->event0 当一些外接控制设备(鼠标、键盘&#xff0c;wifi&#xff0c;触摸屏&am…

4.1_7 文件共享

文章目录 4.1_7 文件共享&#xff08;一&#xff09;基于索引结点的共享方式&#xff08;硬链接&#xff09;&#xff08;二&#xff09;基于符号链的共享方式&#xff08;软链接&#xff09; 总结 4.1_7 文件共享 注意&#xff1a;多个用户共享同一个文件&#xff0c;意味着系…

单片机第四季-第二课:uCos2源码-BSP

1&#xff0c;初始uCos2 文件中uC开头的为uCos相关的。 2&#xff0c;uCos2源码工程建立 建立Source Insight工程 寻找main函数 (1)RTOS其实就是一个大的裸机程序&#xff0c;也是从main开始运行的 (2)main之前也是有一个汇编的启动文件的 (3)main中调用了很多初始化函数 bsp部…

《你就是孩子最好的玩具·升级版》笔记(一)尊重孩子的感受

目录 简介 经典摘录 简介 作者是&#xff08;美&#xff09;金伯莉布雷恩。奠定父母与孩子一生亲密关系的情感引导书。 什么是情感引导&#xff1f; 情感引导式教育的核心&#xff0c;就是教我们的孩子如何去合理地认知以及表达自己的感受&#xff0c;书中更侧重于在这方面为…

【NBUOJ刷题笔记】递推_递归+分治策略2

0. 前言 PS&#xff1a;本人并不是集训队的成员&#xff0c;因此代码写的烂轻点喷。。。本专题一方面是巩固自己的算法知识&#xff0c;另一方面是给NBU学弟学妹们参考解题思路&#xff08;切勿直接搬运抄袭提交作业&#xff01;&#xff01;&#xff01;&#xff09;最后&…

【matlab】如何批量修改图片命名

【matlab】如何批量修改图片命名 (●’◡’●)先赞后看养成习惯😊 假如我的图片如下,分别是1、2、3、4、5的命名 需求一:假如现在我需要在其后面统一加上_behind字符串,并且保留原命名,同时替换掉原先的图片,也就是不copy新的一份,直接在原文件夹中处理,我们可以进行…

软件杯 深度学习 python opencv 动物识别与检测

文章目录 0 前言1 深度学习实现动物识别与检测2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存…

openEuler学习总结1(仅供学习参考)

华为的openEuler内核是源于Linux。 openEuler操作系统安装流程 第一步&#xff1a;开启虚拟化 第二步&#xff1a;安装一个虚拟化软件virtualbox 第三步&#xff1a;镜像 第四步&#xff1a;配置 设置虚拟机所在的目录 把网卡类型选择成桥接网卡 挂载镜像 设置完成&#xff0…

YOLOv9详解

1.概述 在逐层进行特征提取和空间转换的过程中&#xff0c;会损失大量信息&#xff0c;例如图中的马在建模过程中逐渐变得模糊&#xff0c;从而影响到最终的性能。YOLOv9尝试使用可编程梯度信息PGI解决这一问题。 具体来说&#xff0c; PGI包含三个部分&#xff0c;&#xff0…

【你也能从零基础学会网站开发】Web建站之jQuery进阶篇 jQuery常见属性和方法概述与使用

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;程序猿、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 jQuery创建新的…

vulhub中Apache Shiro 认证绕过漏洞复现(CVE-2010-3863)

Apache Shiro是一款开源安全框架&#xff0c;提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用&#xff0c;同时也能提供健壮的安全性。 在Apache Shiro 1.1.0以前的版本中&#xff0c;shiro 进行权限验证前未对url 做标准化处理&#xff0c;攻击者可以构造/、//、…

交流互动系统|基于springboot框架+ Mysql+Java+Tomcat的交流互动系统设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java&#xff0c;ssm&#xff0c;springboot的平台设计与实现项目系统开发资源&#xff08;可…

redis学习-String类型的命令介绍以及特殊情况分析

目录 1. set key value 2. get key 3. append key string 4. strlen key 5. incr key 和 decr key 6. incrby key num 和 decrby key num 7. getrange key start end 8. setrange key start string 9. setex key time value 10. setnx key value 11. mset key1 val…

【Web开发】CSS教学(超详细,满满的干货)

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【Web开发】CSS教学(超详细,满满的干货) &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 CSS一. 什么是CSS?1.1 基本语法规范1.2 引入方式1.3 规范 二. CSS选…

【第三章-1】面向对象——类与对象基本概念

目录 1.引例 2.类class 3. 面向对象中什么是对象&#xff1f; 4.类和对象的关系 5.面向对象编程 6.IDEA创建类与对象 7.成员变量 8.IDEA上代码练习成员变量 9.什么是方法 10.包Package&#xff08;详细参考&#xff09; 11.访问修饰符 12.面向对象与面向过程 1.引例…

Docker入门二(应用部署、迁移与备份、DockerFile、docker私有仓库、Docker-Compose)

文章目录 一、应用部署1.MySQL部署2.Redis部署3.Nginx部署 二、迁移与备份1.容器做成镜像2.镜像备份和恢复(打包成压缩包&#xff09; 三、DockerFile0.镜像从哪里来&#xff1f;1.什么是DockerFile2.DockerFile 构建特征3.DockerFile命令描述4.构建一个带vim的centos镜像案例5…

PC-DARTS: PARTIAL CHANNEL CONNECTIONS FOR MEMORY-EFFICIENT ARCHITECTURE SEARCH

PC-DARTS&#xff1a;用于内存高效架构搜索的部分通道连接 论文链接&#xff1a;https://arxiv.org/abs/1907.05737 项目链接&#xff1a;https://github.com/yuhuixu1993/PC-DARTS ABSTRACT 可微分体系结构搜索(DARTS)在寻找有效的网络体系结构方面提供了一种快速的解决方案…

[java基础揉碎]断点调试

一个实际需求: 1.在开发中&#xff0c;新手程序员在查找错误时&#xff0c;这时老程序员就会温馨提示&#xff0c;可以用断点调试&#xff0c; 一步一步的看源码执行的过程&#xff0c;从而发现错误所在。 2.重要提示:在断点调试过程中&#xff0c;是运行状态&#xff0c;是以…