Linux基础知识点(五-信号)
一、信号的基本概念
1.1 信号的概念
信号(signal),又称为软中断信号,用于通知进程发生了异步事件,它是Linux系统响应某些条件而产生的一个事件,它是在软件层次上对中断机制的一种模拟,是一种异步通信方式。
一句话总结:信号本质是一种异步通知机制,用户或操作系统通过发送信号来通知进程某些事情已经发生,进程可以进行后续处理。
1.2 信号的产生
① 通过终端按键产生信号:
用户在终端按某些键时,引发终端产生信号,例如在终端上按Ctrl + C键通常产生中断信号(SIGINT),终止进程。
② 通过系统函数向进程发信号:
进程调用kill(2)函数可以将任意信号发送给另一个进程或进程组,但接收信号和发送信号进程的所有者必须相同,或发送信号进程的所有者是超级用户。在终端通过"kill -SIGNO PID" 也可以将指定的信号发送给指定pid的进程,如kill -SIGINT 4568。
③ 由软件条件产生信号:
当检测到某种软件条件已经发生,将其通知有关进程时也产生信号,例如SIGURG(在网络连接上传来外面的数据)、SIGPIPE(在管道的读进程已终止后,一个进程写此管道)、SIGALRM(进程所设置的闹钟已经超时)。
④ 硬件异常产生信号:
除数为0、无效的内存引用等,这些条件通常由硬件检测到,并通知内核,然后内核为该条件发生时正在运行的进程产生适当的信号。
1.3 信号的通信机制
信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达,事实上, 进程也不知道信号到底什么时候到达。它和中断服务函数一样,在中断发生的时候, 就会进入中断服务函数中去处理,同样的,当进程接收到一个信号的时候,也会相应地采取一些行动。
1.4 信号的种类
我们可以使用" kill -l "命令来查看系统中支持的信号的种类
从图中可以看出,Linux系统支持信号62种信号,每种信号名称都以SIG三个字符开头, 注意,编号为32和33的信号值是不存在的。
可以将这62种信号分为两大类:信号值为1~31的信号属于非实时信号(也称为不可靠信号),它们是从UNIX系统中继承下来的信号,信号值为34~64的信号为实时信号(也称为可靠信号)。
这些信号各自在什么条件下产生,默认的处理动作是什么,可以通过 " man 7 signal " 来查询。
信号值 | 名称 | 描述 | 默认处理 |
---|---|---|---|
1 | SIGHUP | 控制终端被关闭时产生。 | 终止 |
2 | SIGINT | 程序终止(interrupt)信号,在用户键入INTR字符(通常是Ctrl + C)时发出,用于通知前台进程组终止进程。 | 终止 |
3 | SIGQUIT | SIGQUIT 和SIGINT类似,但由QUIT字符(通常是Ctrl + )来控制,进程在因收到SIGQUIT退出时会产生core文件,在这个意义上类似于一个程序错误信号。 | 终止并产生转储文件(core文件) |
4 | SIGILL | CPU检测到某进程执行了非法指令时产生,通常是因为可执行文件本身出现错误, 或者试图执行数据段、堆栈溢出时也有可能产生这个信号。 | 终止并产生转储文件(core文件) |
5 | SIGTRAP | 由断点指令或其它trap指令产生,由debugger使用。 | 终止并产生转储文件(core文件) |
6 | SIGABRT | 调用系统函数 abort()时产生。 | 终止并产生转储文件(core文件) |
7 | SIGBUS | 总线错误时产生。一般是非法地址,包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数,但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。 | 终止并产生转储文件(core文件) |
8 | SIGFPE | 处理器出现致命的算术运算错误时产生,不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。 | 终止并产生转储文件(core文件) |
9 | SIGKILL | 系统杀戮信号。用来立即结束程序的运行,本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号将进程杀死。 | 终止 |
10 | SIGUSR1 | 用户自定义信号。 | 终止 |
11 | SIGSEGV | 访问非法内存时产生,进程试图访问未分配给自己的内存,或试图往没有写权限的内存地址写数据。 | 终止 |
12 | SIGUSR2 | 用户自定义信号。 | 终止 |
13 | SIGPIPE | 这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止,也会产生这个信号。 | 终止 |
14 | SIGALRM | 定时器到期信号,计算的是实际的时间或时钟时间,alarm函数使用该信号。 | 终止 |
15 | SIGTERM | 程序结束(terminate)信号,与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号,如果进程终止不了,才会尝试SIGKILL。 | 终止 |
16 | SIGSTKFLT | 已废弃。 | 终止 |
17 | SIGCHLD | 子进程暂停或终止时产生,父进程将收到这个信号,如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程,这种情况我们应该避免。父进程默认是忽略SIGCHILD信号的,我们可以捕捉它,做成异步等待它派生的子进程终止,或者父进程先终止,这时子进程的终止自动由init进程来接管。 | 忽略 |
18 | SIGCONT | 系统恢复运行信号,让一个停止(stopped)的进程继续执行,本信号不能被阻塞,可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作 | 恢复运行 |
19 | SIGSTOP | 系统暂停信号,停止进程的执行。注意它和terminate以及interrupt的区别:该进程还未结束,只是暂停执行,本信号不能被阻塞,处理或忽略。 | 暂停 |
20 | SIGTSTP | 由控制终端发起的暂停信号,停止进程的运行,但该信号可以被处理和忽略,比如用户键入SUSP字符时(通常是Ctrl+Z)发出这个信号。 | 暂停 |
21 | SIGTTIN | 后台进程发起输入请求时控制终端产生该信号。 | 暂停 |
22 | SIGTTOU | 后台进程发起输出请求时控制终端产生该信号。 | 暂停 |
23 | SIGURG | 套接字上出现紧急数据时产生。 | 忽略 |
24 | SIGXCPU | 处理器占用时间超出限制值时产生。 | 终止并产生转储文件(core文件) |
25 | SIGXFSZ | 文件尺寸超出限制值时产生。 | 终止并产生转储文件(core文件) |
26 | SIGVTALRM | 由虚拟定时器产生的虚拟时钟信号,类似于SIGALRM,但是计算的是该进程占用的CPU时间。 | 终止 |
27 | SIGPROF | 类似于SIGALRM / SIGVTALRM,但包括该进程用的CPU时间以及系统调用的时间。 | 终止 |
28 | SIGWINCH | 窗口大小改变时发出。 | 忽略 |
29 | SIGIO | 文件描述符准备就绪, 可以开始进行输入/输出操作。 | 终止 |
30 | SIGPWR | 启动失败时产生。 | 终止 |
31 | SIGUNUSED | 非法的系统调用。 | 终止并产生转储文件(core文件) |
1.5 实时信号和非实时信号
Linux系统中有许多信号,其中前面 31 个信号都有一个特殊的名字,对应一个特殊的事件, 比如信号值为1的信号SIGHUP(Signal Hang UP),这个信号就是通知系统关闭中断的, 当系统中的一个控制终端被关闭(即挂断,hang up)时,都会产生这个信号。
信号值为1~31的信号属性非实时信号,它主要是因为这类信号不支持排队, 因此信号可能会丢失。比如发送多次相同的信号,进程只能收到一次, 也只会处理一次,因此剩下的相同的信号将被丢弃。而实时信号(信号值为34~64的信号)则不同, 它是支持排队的,发送了多少个信号给进程,进程就会处理多少次。
二、信号的处理
生成信号的事件一般可以归为三大类:程序错误、外部事件以及显式请求。
程序错误如:零作除数、非法存储访问等,这种情况通常是由硬件而不是由Linux内核检测到的, 但由内核向发生此错误的那个进程发送相应的信号;
外部事件如:当用户在终端按下某些键时产生中断生成的信号,当进程超越了CPU或文件大小的限制时, 内核会生成一个信号通知进程;
显式请求如:进程通过使用kill()函数来发送任何信号给其他进程或进程组。
信号的生成既可以是同步的,也可以是异步的:
同步信号大多数是程序执行过程中出现了某个错误而产生的, 由进程显式请求生成的给自己的信号也是同步的。
异步信号是接收进程可控制之外的事件所生成的信号,这类信号一般是进程无法控制的, 只能被动接收,因为进程也不知道这个信号会何时发生,只能在发生的时候去处理它。 一般外部事件总是异步地生成信号,异步信号可在进程运行中的任意时刻产生, 进程无法预期信号到达的时刻,它所能做的只是告诉Linux内核假如有信号生成时应当采取什么行动(这相当于注册信号对应的处理)。
无论是同步还是异步信号,当信号发生时,我们可以告诉Linux内核采取如下3种动作中的任意一种:
忽略信号:大部分信号都可以被忽略,但有两个除外:SIGSTOP和SIGKILL绝不会被忽略。 不能忽略这两个信号的原因是为了给超级用户提供杀掉或停止任何进程的一种手段。 此外,尽管其他信号都可以被忽略,但其中有一些却不宜忽略。例如,若忽略硬件例外(非法指令)信号, 则会导致进程的行为不确定。
捕获信号:这种处理是要告诉Linux内核,当信号出现时调用专门提供的一个函数。 这个函数称为信号处理函数,它专门对产生信号的事件作出处理。
让信号默认动作起作用:系统为每种信号规定了一个默认动作,这个动作由Linux内核来完成, 有以下几种可能的默认动作:
终止进程并且生成内存转储文件,即写出进程的地址空间内容和寄存器上下文至进程当前目录下名为cone的文件中;
终止终止进程但不生成core文件。
忽略信号。
暂停进程。
若进程为暂停状态,恢复进程,否则将忽略信号。
三、信号的保存
3.1 信号其他相关概念
- 实际执行信号的处理动作称为信号递达(Delivery)。
- 信号从产生到递达之间的状态称为信号未决(Pending)。
- 进程可以选择阻塞 (Block )某个信号。
- 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。
- 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
3.2 信号在内核中的表示
- 进程通过二个位图来管理信号的处理过程, 每个信号占用两个位图某一位分别表示阻塞(block)和未决(pending),还有一个函数指针数组表示处理动作。信号产生时,内核在进程控制块(task_struct)中设置该信号的未决标志,直到信号递达才清除该标志。
- 在上图的例子中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
- SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
- SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,且不能抵达,它的处理动作是用户自定义函数sighandler。
3.3 信号集
每个信号在未决和阻塞位图中各占用一位,非0即1,不记录该信号产生了多少次。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,即图中未决和阻塞的位图。这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。
3.4 信号集操作函数
用户只能通过信号集操作函数来操作信号集(sigset_t)。
#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);
- 函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清0,表示该信号集不包含任何有效信号。
- 函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置1,表示该信号集的有效信号包括系统支持的所有信号。
- sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号,若包含则返回1,不包含则返回0,出错返回-1。
- 注意,在使用sigset_t类型的变量之前,一定要调用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信,这四个函数都是成功返回0,出错返回-1。
3.5 sigprocmask
调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集),成功返回0,失败返回-1。
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
参数说明:
how:表示如何修改信号屏蔽字。
set:根据how的参数修改信号屏蔽字的值。
oset:输出型参数,保存信号屏蔽字修改前的值。
假设当前的信号屏蔽字为mask,则how参数如下表。
SIG_BLOCK | set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask = mask | set |
SIG_UNBLOCK | set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask = mask&~set |
SIG_SETMASK | 设置当前信号屏蔽字为set的值,相当于mask = set |
3.6 sigpending
读取当前进程的未决信号集,通过set参数传出,成功返回0,失败返回-1。
#include <signal.h>
int sigpending(sigset_t* set);
四、信号的捕获
4.1 signal()
signal()主要是用于捕获信号,可以改变进程中对信号的默认行为,我们在捕获这个信号后, 也可以自定义对信号的处理行为。
使用signal()时,它需要提前设置一个回调函数,即进程接收到信号后将要跳转执行的响应函数, 或者设置忽略某个信号,才能改变信号的默认行为,这个过程称为“信号的捕获”。 对一个信号的“捕获”可以重复进行,不过signal()函数将会返回前一次设置的信号响应函数指针。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数说明:
signum:signum是指定捕获的信号名称,如果指定的是一个无效的信号, 或者尝试处理的信号是不可捕获或不可忽略的信号(如SIGKILL),errno将被设置为EINVAL。
handler:handler是一个函数指针,它的类型是
void(*sighandler_t)(int)
类型,拥有一个int类型的参数, 这个参数的作用就是传递收到的信号值,返回类型为void。signal()函数会返回一个sighandler_t类型的函数指针,这是因为调用signal()函数修改了信号的行为, 需要返回之前的信号处理行为是哪个,以便让应用层知悉, 如果修改信号的默认行为识别则返回对应的错误代码SIG_ERR。
handler需要用户自定义处理信号的方式,当然还可以使用以下宏定义:
SIG_IGN:忽略该信号。
SIG_DFL:采用系统默认方式处理信号。
注意:如果调用处理程序导致信号被阻塞,则从处理程序返回后, 信号将被解除阻塞。无法捕获或忽略信号SIGKILL和SIGSTOP。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>/* 信号处理函数 */
void signal_handler(int sig)
{printf("\nthis signal number is %d \n",sig);if (sig == SIGINT) {printf("I have get SIGINT!\n\n");/* 恢复信号为默认情况 */signal(SIGINT, SIG_DFL);printf("default processing has been restored\n"); }
}int main(void)
{printf("\nthis is an singal test function\n\n");/* 设置信号处理的回调函数 */signal(SIGINT, signal_handler); while (1) {printf("waiting for the SIGINT signal , please enter \"ctrl + c\"...\n");sleep(1); }exit(0);
}
4.2 sigaction()
sigaction()函数原型如下:
#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
这个函数的参数比signal()函数多了一些,参数区别如下:
signum:指定捕获的信号值。
act:是一个结构体,该结构体的内容如下。
struct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);};
sa_handler是一个函数指针,是捕获信号后的处理函数,它也有一个int类型的参数,传入信号的值,这个函数是标准的信号处理函数。
sa_sigaction则是扩展信号处理函数,它也是一个函数指针,但它比标准信号处理函数复杂的多, 事实上如果选择扩展接口的话,信号的接收进程不仅可以接收到int型的信号值, 还会接收到一个 siginfo_t类型的结构体指针,还有一个void类型的指针,还有需要注意的就是, 不要同时使用sa_handler和sa_sigaction,因为这两个处理函数是有联合的部分(联合体)。
sa_mask是信号屏蔽字,它指定了在执行信号处理函数期间阻塞的信号掩码,被设置在该掩码中的信号, 在进程响应信号期间被临时阻塞。除非使用SA_NODEFER标志,否则即使是当前正在处理的响应的信号再次到来的时候也会被阻塞。
re_restorer则是一个已经废弃的成员变量,不要使用。
sa_flags是指定一系列用于修改信号处理过程行为的标志,由下面的0个或多个标志组合而成:
SA_NOCLDSTOP:如果signum是SIGCHLD,则在子进程停止或恢复时,不会传信号给调用sigaction()函数的进程。 即当它们接收到SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU(停止)中的一种时或接收到SIGCONT(恢复)时, 父进程不会收到通知。仅当为SIGCHLD建立处理程序时,此标志才有意义。
SA_NOCLDWAIT:它表示父进程在它的子进程终止时不会收到SIGCHLD 信号, 这时子进程终止则不会成为僵尸进程。
SA_NODEFER:不要阻止从其自身的信号处理程序中接收信号,使进程对信号的屏蔽无效, 即在信号处理函数执行期间仍能接收这个信号,仅当建立信号处理程序时,此标志才有意义。
SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
SA_SIGINFO:指示使用sa_sigaction成员而不是使用sa_handler 成员作为信号处理函数。
oldact:返回原有的信号处理参数,一般设置为NULL即可。
上面的成员变量绝大部分我们是几乎使用不到的,因为我们如果是对信号的简单处理,直接使用sa_handler处理即可, 根本无需配置siginfo_t这些比较麻烦的信息。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>/* 信号处理函数 */
void signal_handler(int sig)
{printf("\nthis signal number is %d \n",sig);if (sig == SIGINT) {printf("I have get SIGINT!\n\n");printf("The signal is automatically restored to the default handler!\n\n");/* 信号自动恢复为默认处理函数 */}}int main(void)
{struct sigaction act;/* 设置信号处理的回调函数 */act.sa_handler = signal_handler; /* 清空屏蔽信号集 */sigemptyset(&act.sa_mask); /* 在处理完信号后恢复默认信号处理 */act.sa_flags = SA_RESETHAND; sigaction(SIGINT, &act, NULL); while (1){printf("waiting for the SIGINT signal , please enter \"ctrl + c\"...\n\n");sleep(1);}exit(0);
}
五、信号的发送
5.1 kill()
#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int sig);
kill()函数的参数有两个,分别是pid与sig,还返回一个int类型的错误码。
pid的取值如下:
pid > 1:将信号sig发送到进程ID值为pid指定的进程。
pid = 0:信号被发送到所有和当前进程在同一个进程组的进程。
pid = -1:将sig发送到系统中所有的进程,但进程1(init)除外。
pid < -1:将信号sig发送给进程组号为-pid (pid绝对值)的每一个进程。
sig:要发送的信号值。
函数返回值:
0:发送成功。
-1:发送失败。
进程可以通过调用kill()函数向包括它本身在内的其他进程发送一个信号。 如果程序没有发送该信号的权限,对kill函数的调用就将失败,失败的常见原因是目标进程由另一个用户所拥有。 因此要想发送一个信号,发送进程必须拥有相应的权限,这通常意味着两个进程必须拥有相同的用户ID(即你只能发送信号给属于自己的进程, 但超级用户可以发送信号给任何进程)。
kill()函数会在失败时返回-1并设置errno变量。失败的原因可能是:给定的信号无效(errno设置为INVAL)、 发送进程权限不够(errno设置为EPERM)、目标进程不存在(errno设置为ESRCH)等情况。
5.2 raise()
raise()函数也是发送信号函数,不过与 kill()函数所不同的是, raise()函数只是进程向自身发送信号的,而没有向其他进程发送信号, 可以说kill(getpid(),sig)等同于raise(sig)。
#include <signal.h>int raise(int sig);
raise()函数只有一个参数sig,它代表着发送的信号值,如果发送成功则返回0,发送失败则返回-1, 发送失败的原因主要是信号无效,因为它只往自身发送信号,不存在权限问题,也不存在目标进程不存在的情况。
5.3 alarm()
alarm()也称为闹钟函数,它可以在进程中设置一个定时器,当定时器指定的时间seconds到时, 它就向进程发送SIGALARM信号。其函数原型如下:
#include <unistd.h>unsigned int alarm(unsigned int seconds);
如果在seconds秒内再次调用了alarm()函数设置了新的闹钟,则新的设置将覆盖前面的设置, 即之前设置的秒数被新的闹钟时间取代。它的返回值是之前闹钟的剩余秒数,如果之前未设闹钟则返回0。 特别地,如果新的seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。
相关文章:
Linux基础知识点(五-信号)
一、信号的基本概念 1.1 信号的概念 信号(signal),又称为软中断信号,用于通知进程发生了异步事件,它是Linux系统响应某些条件而产生的一个事件,它是在软件层次上对中断机制的一种模拟,是一种异…...
SpringBoot 一个注解实现数据脱敏
什么是数据脱敏 数据脱敏是指对某些敏感信息,例如姓名、身份证号码、手机号、固定电话、银行卡号、邮箱等个人信息,通过脱敏算法进行数据变形,以保护敏感隐私数据。 数据脱敏通常涉及以下几种主要方法: 替换: 将原始…...
记录:开始学习网络安全
本文持续更新学习进度 背景 在私企干了5年虚拟化、云原生相关的运维,学到了很多,但不成体系。老板是清华毕业法国留学在德勤干过,最后回国创业的野路子。我工作是为了更好的生活,我挺担心老板因为家庭变故或者炒个原油宝&#x…...
C语言—第1次作业:编译与连接基础知识
常做练习巩固知识 本次作业答案链接如下: 答案解析——C语言—第1次作业:编译与连接基础知识 1.字符串的结束标志是:( ) A.是0 B.是EOF C. 是\0 D.是空格 2.关于C语言关键字说法正确的是:( ) A.关…...
not attached to window manager问题解决
关于出现这个问题,一般是因为Activity已经在finish了,但是还在dialog.show(),或者dialog.dismiss().导致window manager无法管理dialog。解决办法如下: /** * 20210913 安全关闭对话框 . * 避免报:not attac…...
影视后期: PR调色处理,调色工具面板介绍
写在前面 整理一些影视后期的相关笔记博文为 Pr 调色处理,涉及调色工具面板简单认知包括 lumetri 颜色和范围面板理解不足小伙伴帮忙指正 元旦快乐哦 _ 名词解释 饱和度 是指色彩的鲜艳程度,也被称为色彩的纯度。具体来说,它表示色相中灰色…...
ARM AArch64的虚拟化(virtualization)详解(上)
目录 一、概述 开始之前 二、虚拟化介绍 为什么虚拟化很重要...
计算机组成原理知识总结
目录 第一章、计算机系统概述知识框架:1.冯诺依曼机和存储程序的概念?2.计算机的工作过程?3.在计算机系统结构中,什么是编译?什么是解释?4.描述一下指令执行过程?1) 取指令: PC 一&g…...
springboot学习(八十五) 解决springboot3.2找不到资源无法抛出404错误的问题
前言 springboot3.2以下可以定义ErrorPageRegistrar将404错误转发到一个接口地址,但升级到springboot3.2(spring6.1)后,该配置不生效,抛出了500错误。 以前的错误页面处理如下: ConditionalOnClass(ErrorPageRegist…...
OpenHarmony 应用通用签名
一.背景 由于hap包需要经过签名才能安装到设备上,在DevEco Studio可以进行自动签名,但是自动签名只能安装在当前的设备上,在其他设备上不能安装,所以我们需要进行通用的手动签名,手动签名HarmonyOS和OpenHarmony流程是…...
Redis:原理+项目实战——Redis实战1(session实现短信登录(并剖析问题))
👨🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习 🌌上期文章:Redis:原理速成项目实战——Redis的Java客户端 📚订阅专栏:Redis速成 希望文章对你们有所帮助…...
交叉编译aarch64架构支持openssl的curl、libcurl
本文档旨在指导读者在x86_64平台上交叉编译curl和openssl库以支持aarch64架构。在开始之前,请确保您的系统环境已正确配置。 1. 系统环境准备 系统是基于Ubuntu 20.04 LTS,高版本可能会有问题。首页,安装必要的开发工具和库文件。打开终端并…...
扩展名是.KEY的文件可能有不同的存在,打开方式也因此不同
本文解释了使用KEY文件扩展名的所有不同格式,以及如何在可能的情况下打开和转换每种格式。 KEY文件的定义 KEY文件扩展名可能是用于注册软件程序的纯文本或加密的通用许可证密钥文件。不同的应用程序使用不同的KEY文件来注册各自的软件,并证明用户是合…...
软件工程总复习笔记
软件工程课程复习提纲 文章目录 软件工程课程复习提纲一、基本知识点1. 软件工程的概念及目标2. 软件危机的概念及典型表现3. 瀑布模型的概念及特点4. 快速原型模型的特点5. 螺旋模型的基本思想6. 软件生命周期的概念及划分为哪几个阶段7. 软件需求的定义8. 常见的软件需求获取…...
蓝桥杯-每日刷题-030
打印等边三角形 一、题目要求 题目描述 输出等边三角形:输入n值,输出高度为n的等边三角形。输入格式 输入存在多组测试数据。对于每组测试数据输入一个正整数n(1<n<100)。输出格式 对于每组测试数据输出对应的等边三角形。每组测试数据最后输出一…...
AI赋能游戏开发,如何更好地处理随之而来的海量数据,更好地利用开发游戏?
人工智能(AI)正在改变我们所知的游戏行业。它为3A工作室、独立开发者和业余爱好者提供了工具,让他们能够更轻松地创建以前需要大量时间和资源的项目。尤其是,虚幻引擎的AI工具已经取得了显著的进步。 虚幻引擎AI拥有专门用于游戏…...
Serverless架构学习路线及平台对比
在云计算领域,Serverless架构已经成为了一个重要的趋势。本文将为你提供一条清晰的Serverless架构学习路线,帮助你系统地掌握这个领域的知识,并对比国内外的Serverless平台的优缺点。 一、基础理论学习 首先,我们需要理解Server…...
解决ROS含动态参数的Config文件无法正确识别的错误
问题描述 功能包名为paddle_detection 在工作空间下, 通过catkin_make可以正常通过编译且执行无异常, 可以通过bloom-generate rosdebian生成依赖 但是在将其打包成deb包的过程中fakeroot debian/rules binary报错 fatal error: paddle_detection/paddle_detectionConfig.…...
探索 PyTorch 中的 torch.nn 模块**(1)
目录 引言 torch.nn使用和详解 Parameter 函数作用 使用技巧 使用方法和示例 UninitializedParameter 特点和用途 可进行的操作 使用示例 UninitializedBuffer 特点和用途 可进行的操作 使用示例 Module**(重点) 关键特性和功能 举例说…...
【WPF.NET开发】预览事件
本文内容 先决条件预览标记为“已处理”的事件通过控件解决事件禁止问题 预览事件,也称为隧道事件,是从应用程序根元素向下遍历元素树到引发事件的元素的路由事件。 引发事件的元素在事件数据中报告为Source 。 并非所有事件场景都支持或需要预览事件。…...
JDBC->SpringJDBC->Mybatis封装JDBC
一、JDBC介绍 Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标。我们…...
ts中的keyof 关键字
const getVal <T,K extends keyof T>(obj:T,key:K) : T[K]>{return obj[key]; }使用了 keyof 关键字。keyof 是 TypeScript 的一个特性,它返回一个字符串字面量类型,表示对象类型的所有属性键的联合类型。 这段代码定义了一个泛型函数 gatVal&…...
Head First Design Patterns - 装饰者模式
什么是装饰者模式 装饰者模式动态地将额外责任附加到对象上。对于拓展功能,装饰者提供子类化的弹性替代方案。 --《Head First Design Patterns》中的定义 为什么会有装饰者模式 根据上述定义,简单来说,装饰者模式就是对原有的类,…...
MySQL 执行过程
MySQL 的执行流程也确实是一个复杂的过程,它涉及多个组件的协同工作,故而在面试或者工作的过程中很容易陷入迷惑和误区。 MySQL 执行过程 本篇将以 MySQL 常见的 InnoDB 存储引擎为例,为大家详细介绍 SQL 语句的执行流程。从连接器开始&…...
判断电话号码是否重复-excel
有时候重复的数据不需要或者很烦人,就需要采取措施,希望以下的方法能帮到你。 1.判断是否重复 方法一: 1)针对第一个单元格输入等号,以及公式countif(查找记录数的范围,需要查找的单元格) 2…...
【Java开发岗面试】八股文—Java虚拟机(JVM)
声明: 背景:本人为24届双非硕校招生,已经完整经历了一次秋招,拿到了三个offer。本专题旨在分享自己的一些Java开发岗面试经验(主要是校招),包括我自己总结的八股文、算法、项目介绍、HR面和面试…...
【Linux】Linux 下基本指令 -- 详解
无论是什么命令,用于什么用途,在 Linux 中,命令有其通用的格式: command [-options] [parameter] command:命令本身。-options:[可选,非必填]命令的一些选项,可以通过选项控制命令的…...
Eureka注册及使用
一、Eureka的作用 Eureka是一个服务注册与发现的工具,主要用于微服务架构中的服务发现和负载均衡。其主要作用包括: 服务提供者将自己注册到Eureka Server上,包括服务的地址和端口等信息。服务消费者从Eureka Server上获取服务提供者的地址…...
Ubuntu之修改时区/时间
1、查看当前时间及时区状态 sudo timedatectl status # 显示当前时区为Asia/Shanghai 2、查看当前系统时间 sudo date 3、查看当前系统时间及时区 sudo date -R # 显示当前时间及对应时区,时区为“0800”北京时区 4、修改硬件时间 修改日期格式:…...
4、内存泄漏检测(多线程)
4、内存泄漏多线程 多线程下使用Valgrind 工具的memcheck检查. 安装 sudo apt install valgrind使用 valgrind --toolmemcheck --leak-checkfull ./app_main 指令效果如下所示. wqwq-Virtual-Machine:~/work/test_zlog/build$ valgrind --toolmemcheck --leak-checkfull .…...
四川南充房产网/宁波百度seo点击软件
Insatll (安装)//> 使用composer直接安装composer require graham-campbell/markdown//> 或在composer.json文件require中添加如下:"require": {"graham-campbell/markdown": "^7.0"}//> 使用下面命令更新composer.json依赖…...
wordpress下载网页/20个排版漂亮的网页设计
【小白从小学Python、C、Java】【计算机等级考试500强双证书】【Python-数据分析】将字符串生成艺术字pyfiglet.figlet_format选择题以下关于python代码表述错误的一项是?import pyfigletmyText"python"print("【执行】pyfiglet.figlet_format")resultpyf…...
wordpress自定义查询/百度seo关键词优化软件
开发环境 windows7 64、intellij idea 14.1.5、spark-1.5.2、scala 2.0.4、java1.7、maven3.05 将spark中的assembly包引入即可使用local模式运行相关的scala任务,注意不要使用scala2.11,非要使用的话先用这个版本的scala编译一遍spark哈 代码部分 pom文件 先附…...
投资平台/廊坊seo关键词排名
css多种书写格式 行内样式 代码直接写在标签内部 <!--书写css第一种方式,行内样式--> <div style"color: red">css第一种书写格式</div>内联样式 在head标签之间加上一对style标签,在其中编写css代码 <style>/*书写css代码的…...
织梦怎么用模板建站/网络优化的意义
用c写了一个简单的两人对战命令行五子棋游戏。1. 带界面,界面菜单有三个选项:a (棋盘尺寸 20x20), b (伪30x30尺寸,暂时留白),c(退出)。 2. 棋盘由 0-399 这4…...
wordpress系统介绍/深圳知名网络优化公司
在当今竞争激烈的市场环境下,企业想要获得更多的市场份额,拓展更多的客户,必须要进行拓客工作。而在拓客过程中,采集工具是必不可少的工具之一。采集工具可以帮助企业快速获取目标客户的信息,并进行有效的沟通和跟进&a…...