【Linux从入门到精通】信号(初识信号 信号的产生)
本篇文章会对Linux下的信号进行详细解释。主要内容是什么是信号、信号的产生、核心转储等问题。希望本篇文章会对你有所帮助。
文章目录
引入
一、初识信号
1、1 生活中的信号
1、2 Linux 下的信号
1、3 信号+进程所得的初识结论
二、信号的产生
2、1 用户通过终端输入产生信号
2、1、1 理解组合键变成信号
2、1、2 验证ctrl + c 对应 (2)SIGINT信号 (signal()函数)
2、2 核心转储(拓展)
2、3 系统调用接口产生信号
2、4 软件条件产生信号
2、5 由硬件异常产生信号
三、总结
🙋♂️ 作者:@Ggggggtm 🙋♂️
👀 专栏:Linux从入门到精通 👀
💥 标题:信号产生💥
❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️
引入
在Linux系统中,信号是一种轻量级的通信机制,可以用于实现进程之间的协作和通信。每个信号都有一个唯一的编号,通常以SIG开头,例如SIGINT、SIGTERM等。这些信号的含义和行为在Linux系统中是标准化的,但也可以通过自定义信号处理程序来改变它们的行为。
Linux信号在各种情况下都有广泛的应用,从终端用户通过Ctrl+C发送中断信号,到系统管理员使用信号来管理和监控进程,以及进程之间通过信号进行通信和协作。因此,理解Linux信号是系统管理员和开发人员的重要技能,有助于更好地控制和管理Linux系统中的进程。
一、初识信号
1、1 生活中的信号
其实在生活中,我们也经常有意无意的接受信号。比如,玩游戏时队友发送的请求集合、订购外卖时快递员到了你楼下给你打电话,你也收到快递到来的通知等等。古代战争传递信号的方式是烽烟(烽火)。
但是当你收到信号时,你就会立即处理吗?实际上可能并不会。例如,外卖到了但是你正在打游戏,需5min之后才能去取快递。那么在在这5min之内,你并没有下去去取快递,但是你是知道有快递到来了。也就是取快递的行为并不是一定要立即执行,可以理解成“在合适的时候去取”。
我们接收到信号,并且处理时会有很多处理方法。例如我们取回来快递,就要开始处理快递了。而处理快递一般方式有三种:
- 执行默认动作(幸福的打开快递,使用商品);
- 执行自定义动作(快递是零食,你要送给你你的女朋友);
- 忽略快递(快递拿上来之后,扔掉床头,继续开一把游戏。
1、2 Linux 下的信号
Linux信号通常由操作系统或其他进程发送给目标进程,可以用于多种目的,例如中断进程、终止进程或请求进程执行某个特定操作。本质是一种通信机制。
标准信号是一组在Linux系统中具有固定编号和含义的信号。举个例子:我们平常在Linux下进程会使用Ctrl+C来终止当前的进程。这个本质就是向进程发送了一个2号信号。Linux下有很多信号,具体如下图:
实际上一共是有62个信号,因为并没有32号和33号信号。本篇文章重点讲解普通信号,也就是1~31号信号。还有一种信号是实时信号。实时信号是一组具有不同编号和含义的信号,通常用于高优先级任务和实时系统。实时信号的编号范围从34到64。
我们这里先给出普通信号的编号、名称和含义,下文也会对一些重点信号进行讲解:
- SIGHUP(1): 挂起信号。
- SIGINT(2): 中断信号。
- SIGQUIT(3): 退出信号。
- SIGILL(4): 非法指令信号。
- SIGTRAP(5): 跟踪/陷阱信号。
- SIGABRT(6): 中止信号。
- SIGBUS(7): 总线错误信号。
- SIGFPE(8): 浮点异常信号。
- SIGKILL(9): 强制终止信号。
- SIGUSR1(10): 用户自定义信号1。
- SIGSEGV(11): 段错误信号。
- SIGUSR2(12): 用户自定义信号2。
- SIGPIPE(13): 管道破裂信号。
- SIGALRM(14): 超时信号。
- SIGTERM(15): 终止信号。
- SIGSTKFLT(16): 协处理器栈错误信号。
- SIGCHLD(17): 子进程状态改变信号。
- SIGCONT(18): 继续执行信号。
- SIGSTOP(19): 停止信号。
- SIGTSTP(20): 终端停止信号。
- SIGTTIN(21): 后台进程尝试读终端信号。
- SIGTTOU(22): 后台进程尝试写终端信号。
- SIGURG(23): 紧急情况信号。
- SIGXCPU(24): 超出CPU时间限制信号。
- SIGXFSZ(25): 超出文件大小限制信号。
- SIGVTALRM(26): 虚拟定时器信号。
- SIGPROF(27): 专用定时器信号。
- SIGWINCH(28): 窗口大小改变信号。
- SIGIO(29): 异步IO信号。
- SIGPWR(30): 电源故障信号。
- SIGSYS(31): 非法系统调用信号。
通过上述Ctrl+C来终止当前的进程,那么这里会有一个疑问:进程为什么能够识别出用户所发送的信号呢?下面会给出一些结论。
1、3 信号+进程所得的初识结论
同我们上述所列举的生活中的信号和Liunx下的信号,我们大概也能知道以下结论:
- 进程要处理信号,必须具备信号“识别”的能力(看到+处理动作)。
- 凭什么进程能够“识别”信号呢?原因是由于操作系统提供了信号处理机制,通过注册和处理信号处理函数,进程可以对不同的信号做出相应的响应和处理。根本上就是程序员已经在底层都处理好了。
- 信号产生是随机的,进程可能正在忙自己的事情,所以,信号的后续处理,可能不是立即处理的!
- 进程会临时的记录下对应的信号,方便后续进行处理。
- 在什么时候处理呢?合适的时候。(下文会详细解释)
- 一般而言,信号的产生相对于进程而言是异步的。
什么是异步呢?异步是指事件的发生和处理是相互独立、不同步进行的。在计算机编程中,异步操作指的是程序在执行某个操作时,不需要等待该操作完成,而可以继续执行下面的代码,在操作完成后通过回调或其他方式得到结果。
举例来说,假设有一个在线聊天应用程序,用户可以发送消息给其他用户。当用户发送一条消息时,常见的做法是通过网络将消息发送给接收方,然后等待接收方的响应,最后再执行下一步操作。
但如果使用异步的方式,则用户在发送消息之后可以继续进行其他操作,而不需要等待对方的响应。一旦对方接收到消息并做出处理,系统会通知发送方消息已经成功发送,或者提供相应的错误信息。
这种异步的方式可以提高用户体验,因为用户不需要一直等待操作的完成,可以同时进行其他操作。同时也可以提高系统的并发性能,充分利用计算资源。
在编程中,常见的异步操作包括网络请求、文件读写、数据库操作等。通过使用异步操作,可以避免因阻塞等待而导致程序性能下降或产生无响应的情况,提升程序的效率和响应速度。
二、信号的产生
我们大概了解信号的概念后,再来看一下信号都是在哪些情况下产生的。在Linux下,信号可以由多种方式产生。以下是一些常见的信号产生方式:
- 用户通过终端输入:例如按下Ctrl+C键产生的SIGINT信号,用于中断进程的执行。
- 硬件异常:当发生硬件故障或错误时,操作系统会发送相应的信号给进程,例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
- 软件条件:进程可以根据满足特定条件时发送信号给自己或其他进程。本篇文章主要介绍alarm函数 和SIGALRM信号。
- 系统调用:某些系统调用可以触发信号。例如,kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。
下面会对每种产生信号的方式进行详解。
2、1 用户通过终端输入产生信号
2、1、1 理解组合键变成信号
上述了解到了:Ctrl+C产生(2)SIGINT信号。但是组合键怎么就变成信号了呢?
我们可以简单了理解为:Ctrl+C产生SIGINT信号的行为只是命令行界面中的一种约定。具体是:用户按下Ctrl+C后,键盘输入产生一个硬件中断,被OS获取(OS能识别我们所输入的组合键),解释成信号,发送给目标前台进程,前台进程因为收到信号,进而引起进程退出。
在上述的情况中,我们知道了操作系统解释完后将信号发送给了进程。那么信号是保存在哪里呢?答案是对应进程的数据结构位图中!下文也会对此进行详解。那么发送信号的本质是操作系统向进程中写信号,不就是修改对应的进程控制块(PCB)中的内核位图数据结构吗!!!
2、1、2 验证ctrl + c 对应 (2)SIGINT信号 (signal()函数)
在验证之前,我们先来学习一下signal()函数的使用。signal()函数是一个用于处理信号的函数,它允许我们定义信号处理程序来捕获和处理系统中产生的各种信号。具体如下图:
下面是signal()函数的参数解释:signumhandlerSIGINT
参数:
- signum:表示要捕获或处理的信号编号。例如,SIGINT表示键盘中断信号。
- handler:表示信号处理程序的指针。它可以是一个指向函数的指针,也可以是某些特定的常量。我们也可以自定义handler。
- 如果handler的值为SIG_IGN,表示忽略对该信号的处理。
- 如果handler的值为SIG_DFL,表示使用默认的信号处理方式。
我们在对第二参数进行解释一下。在上文中也提到过信号的处理方式:1、默认。2、忽略。3、自定义捕捉。当我们传入自定义函数时,该信号就会进行自定义捕捉。
下面是一个详细的示例使用signal函数来验证ctrl + c 对应 (2)SIGINT信号 :
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h>void signal_handler(int signum) {printf("Received signal: %d\n", signum); }int main() {// 设置信号处理函数signal(SIGINT, signal_handler);printf("Signal handling example. Press Ctrl+C to send a SIGINT signal.mypid:%d\n",getpid());// 进入一个循环,在循环中不进行任何操作,等待信号发生while(1){sleep(1);}return 0; }
在这个示例中,我们定义了一个信号处理函数signal_handler,该函数在收到信号时会被调用,并打印接收到的信号编号。
接下来,在主函数main中,我们通过调用signal函数来设置对SIGINT信号(即Ctrl+C)的处理方式。将signal(SIGINT, signal_handler)作为参数传递给signal函数,表示在接收到SIGINT信号时,调用signal_handler函数进行处理。
然后,我们输出一个提示信息,并进入一个无限循环,在循环中不进行任何操作,只是通过sleep函数暂停一秒钟,等待信号的发生。
当我们在运行程序时,按下Ctrl+C组合键,会发送SIGINT信号。这时,由于我们设置了对SIGINT信号的处理方式为调用signal_handler函数,所以程序会输出"Received signal: 2"(2为SIGINT的信号编号)的消息,并且程序也不会终止。表示成功捕获并处理了SIGINT信号。具体如下图:
signal函数,仅仅是修改进程对特定信号的后续处理动作,不是直接调用对应的处理动作。如果后续没有任何SIGINT信号产生,signal_handler会不会被调用呢?答案是永远也不会被调用。当只有SIGINT信号产生时,才会调用signal_handler函数。
2、2 核心转储(拓展)
在Linux下,我们可通过指令:man 7 signal ,来查看信号的详细信息。如下图:
我们直观的看到,Action中有:Term、Core、Ign、Cont、Stop。在其中主要是Term、Core两种。Term 就是终止的意思。那么Core呢?Core也是有终止的意思,但是在终止进程前,还会生成一个核心转储(core dump)文件。
我们在进程等待(进程的控制(进程退出+进程等待))中提到过,但是并没有进行详细解释。具体如下图:
那么回到我们的问题:核心存储是什么呢?用来干什么的呢?我们接着往下看。
核心转储(core dump)是指在计算机系统中,当发生严重错误或异常情况导致程序无法正常运行时,系统会将程序当前的内存状态和相关信息保存到一个磁盘文件中,该文件就被称为核心转储文件(core dump file)。核心转储文件包含了程序崩溃时的堆栈信息、寄存器状态、全局变量值等关键信息。通过分析核心转储文件,可以帮助开发人员或调试人员确定程序崩溃的原因和位置,并进行问题排查和调试。
但是,在我们的云服务器上,核心存储功能是被关闭的。一个进程允许产生多大的core文件取决于进程的Resource Limit(这个信息保存 在PCB中)。默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。
当然,我们可先查看一下是否能够形成核心存储文件。指令为:ulimit -a。如下图:默认核心存储文件最大为0kb。是不可生成的。可以通过指令:ulimit -c 10240 ,来修改默认核心存储文件的最大值。具体如下图:
我们就行 (3) SIGQUIT信号来测试。代码如下:
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> int main() {// 设置信号处理函数signal(SIGQUIT, SIG_DFL);// 进入一个循环,在循环中不进行任何操作,等待信号发生while(1){sleep(1);}return 0; }
信号(3) SIGQUIT 所对应的组合键为 ctrl+‘\’。我们来看一下运行结果:
为了让结果更加直观,我们不放创建子进程,然后用特殊的方式让子进程退出,再将子进程的退出信号和core dump 标志打印出来。具体结合下图和代码理解:
int main() {pid_t id = fork();if(id == 0){cout << "i am child:" << getpid()<< endl;sleep(1);int a = 100;a /= 0;exit(0);}cout<<"i am father:"<<getpid()<<endl;int status = 0;waitpid(id, &status, 0);cout << "父进程:" << getpid() << " 子进程:" << id << \ " exit sig: " << (status & 0x7F) << " is core: " << ((status >> 7) & 1) << endl;return 0; }
上述代码中有一个除0错误。而它发生时,会产生(8)SGIGFPE 信号,也会发生核心转储。运行结果如下:
我们看到了退出信号确实为8,且core dump标记为变成1。表示发生了核心转储。那么生成的核心转储文件有什么用呢?我们可通过调试,加载核心转储文件后可直接看到所对应的错误信息。指令是:core-file core.27736。具体如下图:
2、3 系统调用接口产生信号
如何理解系统调用接口产生信号呢?首先是我们用户进行系统调用接口,然后操作系统会执行对应的系统代码。其中操作系统会自动提取我们所传入的参数,再向目标进程写信号。也就是修改对应进程的位图数据结构。最后进程会进行相关的处理操作。
系统调用接口也可用于产生各种不同类型的信号。下面列举了几个常见的系统调用接口,它们可用于产生不同的信号:
kill(pid, sig): 这个系统调用接口用于向指定进程发送SIGKILL信号。通过指定pid参数为目标进程的进程ID,通过sig参数指定要发送的信号。
raise(sig): 这个系统调用接口用于向当前进程自身发送信号。通过指定sig参数来选择要发送的信号。
abort():SIGABRT可以被捕捉,但是捕捉之后依然会让进程终止,这就是SIGABRT的特点就像exit函数一样,abort函数总是会成功的,所以没有返回值。
sigaction(sig, new_action, old_action): 这个系统调用接口用于设置信号处理程序。通过指定sig参数表示要设置的信号,通过new_action参数传递新的信号处理程序,通过old_action参数获取之前的信号处理程序。
下文我们也会用到系统调用接口产生相应的信号。
2、4 软件条件产生信号
当一个程序通过软件条件产生信号时,它可以通知其他程序或系统内核发生了某个特定的事件或状态的改变。以下是一个例子来详细解释这个过程:
假设我们有一个服务管理程序,该程序负责监控某个服务器上的各种服务的运行情况。服务管理程序需要检查每个服务是否正常运行,如果发现某个服务停止工作,它应该发送一个信号给系统管理员,以便及时采取措施解决问题。
下面我们来看一个用alarm产生信号。代码如下:
typedef function<void ()> func; vector<func> callbacks;uint64_t count = 0;void showCount() {// cout << "进程捕捉到了一个信号,正在处理中: " << signum << " Pid: " << getpid() << endl;cout << "final count : " << count << endl; } void showLog() {cout << "这个是日志功能" << endl; } void logUser() {if(fork() == 0){execl("/usr/bin/who", "who", nullptr);exit(1);}wait(nullptr); }void catchSig(int signum) {for(auto &f : callbacks){f();}alarm(1); } static void Usage(string proc) {cout << "Usage:\r\n\t" << proc << " signumber processid" << endl; }int main(int argc, char *argv[]) {signal(SIGALRM, catchSig);callbacks.push_back(showCount);callbacks.push_back(showLog);callbacks.push_back(logUser);alarm(1);while(true) count++;return 0; }
这段代码是一个示例程序,它使用了信号处理、回调函数和进程控制相关的操作。下面对代码进行详细解释:
- 首先,定义了一个函数指针类型
func
,该类型表示一个无返回值、无参数的函数。- 创建了一个名为
callbacks
的向量(vector),用于存储回调函数。- 定义了一个名为
count
的64位整数变量,初始值为0。- 定义了三个函数:
showCount()
、showLog()
和logUser()
,分别用于显示count
的值、打印日志和查看当前登录用户。catchSig()
函数用于捕获信号,并依次调用存储在callbacks
中的回调函数。在本例中,catchSig()
会被设置成SIGALRM信号的处理函数。Usage()
函数用于显示程序的使用方法。- 在
main()
函数中,首先注册了SIGALRM信号的处理函数为catchSig()
。- 接下来,将
showCount()
、showLog()
和logUser()
这三个函数添加到callbacks
中。- 调用
alarm(1)
函数,设置一个定时器,每隔1秒钟触发一次SIGALRM信号,从而调用catchSig()
函数。- 使用一个无限循环,不断递增
count
的值。整个程序的运行过程如下:
- 注册SIGALRM信号处理函数
catchSig()
。- 将
showCount()
、showLog()
和logUser()
这三个函数添加到callbacks
中。- 调用
alarm(1)
设置定时器,1秒后触发SIGALRM信号,并调用catchSig()
函数。- 在
catchSig()
函数中,依次调用存储在callbacks
中的函数。showCount()
函数会显示当前count
的值,showLog()
函数会打印日志信息,logUser()
函数会通过创建子进程调用/usr/bin/who
命令查看当前登录用户。- 定时器再次启动,继续循环执行。
2、5 由硬件异常产生信号
除0错误就是硬件异常。包括对野指针的访问修改,也是硬件异常产生信号来终止程序的。
为什么说除0是硬件异常错误呢?所有的计算操作都是在cpu中进行的,cpu中有一个状态寄存器(对外是不可见的,也是不可被修改的),寄存器内有对应的状态标记位(溢出标记位)。OS会自动进行计算完毕之后的检测的!如果溢出标记位是1,OS里面识别到有溢出问题,立即只要找到当前谁在运行提取PID,OS完成信号发送的过程,进程会在合适的时候,进行处理即可。
如何理解野指针或者越界问题呢?
首先都必须通过地址,找到目标位置。我们语言上面的地址,全部都是虚拟地址。将虚拟地址转成物理地址。转换的过程中需要通过页表+MMU(Memory Manager Unit,硬件! ! )。在转换时,发现野指针是越界访问或者非法地址。MMU转化的时候,一定会报错!此时就会发出信号来终止程序。
注意:一旦出现硬件异常,进程一定会退出吗?不一定!一般默认是退出,但是我们即便不退出,我们也做不了什么。当我们不退出时,但也并没有对异常进行任何修改,寄存器中任然保留异常。则会进入死循环报错。
三、总结
本篇文章详细解释了信号是怎么产生的。并且知道了写信号的本质就是修该进程控制块内容等等。
而我们还留下了一系列问题:在合适的时候会处理信号。这里的合适的时候具体是什么呢?同时信号的保存还有很多细节没有讲解。还有最后的信号处理工作也没有详解。我们会在下篇文章进行详细解释!!!感谢阅读ovo~
相关文章:
【Linux从入门到精通】信号(初识信号 信号的产生)
本篇文章会对Linux下的信号进行详细解释。主要内容是什么是信号、信号的产生、核心转储等问题。希望本篇文章会对你有所帮助。 文章目录 引入 一、初识信号 1、1 生活中的信号 1、2 Linux 下的信号 1、3 信号进程所得的初识结论 二、信号的产生 2、1 用户通过终端输入产生信号 …...
Golang综合项目实战(一)
Golang综合项目实战(一) 01-项目简介02-项目架构、术语、运行结果03-创建并初始化项目04-创建用户模型和错误处理05-创建密码加密工具类06-保存密码之前的hooks07-创建用户名密码验证工具类08-用户数据库操作逻辑09-操作用户service10-创建商品分类模型…...
springmvc 获取项目中的所有请求路径
springboot/springmvc 获取项目中的所有请求路径 1. 编写业务代码 Autowiredprivate WebApplicationContext applicationContext;GetMapping("/getAllURL")public RestfulResult getAllURL() {// 获取springmvc处理器映射器组件对象 RequestMappingHandlerMapping无…...
【React学习】React高级特性
1. 函数式组件和类组件区别 函数式组件 函数式组件是一种简单的组件定义方式,它是一个以JavaScript函数为基础的组件。 可以把函数式组件理解为纯函数,它的输入为props,输出为JSX。函数式组件没有状态,也没有生命周期。 functio…...
如何在Windows系统搭建filebrowser私人网盘并实现在外网访问本地内网
Windows系统搭建网盘神器filebrowser结合内网穿透实现公网访问 文章目录 Windows系统搭建网盘神器filebrowser结合内网穿透实现公网访问前言1.下载安装File Browser2.启动访问File Browser3.安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3…...
蓝桥杯官网练习题(算式900)
题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。 小明的作业本上有道思考题: 看下面的算式: (□□□□-□□□□)*□□900其中的小方块代表 0 ~ 9 的数字,这 10 个方块刚好包含了…...
【C++从入门到精通】第1篇:C++基础知识(上)
文章目录 1.1 C语句和程序结构1.1.1 本篇介绍1.1.2 语句1.1.3 函数和主函数1.1.4 解析Hello world1.1.5 语法和语法错误1.1.6 练习时间 1.2 注释1.2.1 单行注释1.2.2 多行注释1.2.3 正确使用注释1.2.4 注释掉代码 1.3 对象和变量1.3.1 数据和值1.3.2 对象和变量1.3.3 变量实例化…...
liunx系统无sudo或管理员权限安装rar解压安装包
liunx无sudo权限安装rar解压安装包 (1)正常liunx安装rar(2)无sudo\root(管理员身份)时如何安装rar (1)正常liunx安装rar 1、下载安装包 WinRAR archiver, a powerful tool to process RAR and ZIP files (r…...
浅析目标检测入门算法:YOLOv1,SSD,YOLOv2,YOLOv3,CenterNet,EfficientDet,YOLOv4
本文致力于让读者对以下这些模型的创新点和设计思想有一个大体的认识,从而知晓YOLOv1到YOLOv4的发展源流和历史演进,进而对目标检测技术有更为宏观和深入的认知。本文讲解的模型包括:YOLOv1,SSD,YOLOv2,YOLOv3,CenterNet,EfficientDet,YOLOv4…...
C++:类和对象(三)
本文主要介绍初始化列表、static成员、友元、内部类、匿名对象、拷贝对象时编译器的优化。 目录 一、再谈构造函数 1.构造函数体赋值 2.初始化列表 3.explicit关键字 二、static成员 1.概念 2.特性 三、友元 1.友元函数 2.友元类 四、内部类 五、匿名对象 六、拷…...
分布式系统第三讲:全局唯一ID实现方案
分布式系统第三讲:全局唯一ID实现方案 本文主要介绍常见的分布式ID生成方式,大致分类的话可以分为两类:一种是类DB型的,根据设置不同起始值和步长来实现趋势递增,需要考虑服务的容错性和可用性; 另一种是类snowflake型…...
Ubuntu之apt-get系列--安装JDK8--方法/教程
原文网址:Ubuntu之apt-get系列--安装JDK8--方法/教程_IT利刃出鞘的博客 简介 本文介绍如何在Ubuntu下安装JDK8。 验证是否安装 可以通过如下命令判断系统是否有安装ssh服务: 命令 java -version 结果 如上所示,表示还没有安装。 查看…...
npm 实现原理
输入 npm install 命令并敲下回车后,会经历如下几个阶段(以 npm 5.5.1 为例): 1.执行工程自身 preinstall 当前 npm 工程如果定义了 preinstall 钩子此时会被执行。 2.确定首层依赖模块 首先需要做的是确定工程中的首层依赖&a…...
国家开放大学 练习题
学前儿童社会教育活动指导 参考试题 一、单项选择题(每小题3分,共30分) 1.《规程》第三十二条规定:“幼儿园应当充分尊重幼儿的个体差异,根据幼儿不同的心理 发展水平,研究有效的活动形式和方法&am…...
Kotlin
函数命名 针对您目前为止学到的 Kotlin 知识,下面给出了一些相关样式指南: 函数名称应采用驼峰式大小写形式,并且应该是动词或动词短语。每个语句都应单独占一行。左花括号应出现在函数开始行的末尾。左花括号前应有一个空格。 变量声明 变…...
和未来合伙人的共同价值观 - 初期
一定要互补,能力板块的互补。 价值观一定要正。 如何管理创业团队? 层级是一个公司逼不得已才要做的,每一个层级的堆积,都会带来一些压力和效率的损失,你一旦把这个团队,变成了十个十个人的团队…...
虚函数表存储的位置(解析C++内存分配及其编译分段)
先上结论:C虚函数表保存在.rdata只读数据段。编译时期由编译器确定虚函数表。虚函数表属于类,类的所有对象共享这个类的虚函数表。 c/c的内存分配 栈(stack):又称堆栈,栈是由编译器自动分配释放…...
JS如何正确销毁 VIDEO 和AUDIO 元素
销毁 VIDEO 元素意味着停止视频的播放,并释放与其相关的所有资源。 一般情况下,我们可以通过调用 VIDEO 元素的 pause() 方法来停止视频播放,然后使用 remove() 方法从 DOM 树中删除元素。 但是,仅仅这样做可能并不能完全卸载 V…...
SpringMvc第四战-【SpringMvc文件上传,下载】
目录 一.SpringMvc文件上传 1.导入依赖(在pom.xml中) 2.配置文件上传解析器(在spring-mvc.xml中) 3.前端标记多功能表单(构建一个jsp界面来操作) 4.将文件写出流,然后写入服务器 5.配置映…...
一种结合白平衡统计信息和曝光信息的软光敏算法专利学习(专利四)
图像分块: 参见下图,一幅图像大小为5*6(像素),每个像素包含R、G、B三个分量,该图像划分为4个分块,第一分块的大小为3*3像素,第二分块的大小为3*3(像素),第三分块的大小为2*3像素,第四…...
华为数通方向HCIP-DataCom H12-821题库(单选题:301-320)
第301题 某台路由器运行 IS-IS,其输出信息如图所示,下列说法错误的是? [R1]display isis sdb local verboseDatabase information for ISIS(1) Level-1 Link State Database LSPID Seq Num Checksum Holdtime…...
dll文件反编译源代码 C#反编译 dotpeek反编译dll文件后export
目录 背景下载安装dotpeek导入dll文件export导出文件参考 背景 项目合作的时候,使用前人的或者其他部门dll文件直接在机台运行,会出现很多问题,逻辑,效率等等,此时我们可以选择对他们的代码进行反编译和重构ÿ…...
地图结构 | 图解占据栅格地图原理(附Matlab建图实验)
目录 0 专栏介绍1 栅格地图1.1 应用场景1.2 基本概念 2 占据栅格地图2.1 更新模型2.2 截断策略 3 仿真实现3.1 算法流程3.2 Matlab实现 0 专栏介绍 🔥附C/Python/Matlab全套代码🔥课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索…...
element-plus点击菜单栏全部展开问题解决
这是由子菜单项的index属性引起的,子菜单项的index属性添加相同的值时就会出现这种情况。所以为每个子菜单项添加不同的index属性值就可解决。...
React 简便获取经纬度
以下是关于React获取定位经纬度的代码解释: import React, { useEffect, useState } from react;const LocationComponent () > {const [latitude, setLatitude] useState(null);const [longitude, setLongitude] useState(null);useEffect(() > {navigat…...
【多线程】线程安全的单例模式
线程安全的单例模式 饿汉模式懒汉模式单线程版多线程版多线程版(改进) 单例模式能保证某个类在程序中只存在 唯一 一份实例, 而不会创建出多个实例,从而节约了资源并实现数据共享。 比如 JDBC 中的 DataSource 实例就只需要一个. 单例模式具体的实现方式, 分成 “饿…...
Competitive Collaboration 论文阅读
论文信息 题目:Competitive Collaboration: Joint Unsupervised Learning of Depth, Camera Motion, Optical Flow and Motion Segmentation 作者:Anurag Ranjan, Varun Jampani, Lukas Balles 来源:CVPR 时间&#x…...
非科班菜鸡算法学习记录 | 代码随想录算法训练营完结!
这俩月终于结束了233333,之后就是反复复习和背八股了吧,然后整整项目春招再投投投,感觉大部分题都有思路了但是做过的题也会没思路,还是要复习 总结 数组: 双指针用的很多,一般一个指向遍历位置࿰…...
C语言实现三字棋
实现以下: 1游戏不退出,继续玩下一把(循环) 2应用多文件的形式完成 test.c. --测试游戏 game.c -游戏函数的实现 game.h -游戏函数的声明 (2)游戏再走的过程中要进行数据的存储,可以使用3*3的二维数组 char bor…...
【LeetCode】35.复杂链表的复制
题目 请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。 示例 1: 输入:head [[7,null],[13,0],[11,4]…...
华为网站建设/营销号
转载请注明地址(http://blog.csdn.net/xinzhangyanxiang/article/details/8522078) 学习概率的时候,大家一定都学过马尔科夫模型吧,当时就觉得很有意思,后来看了数学之美之隐马模型在自然语言处理中的应用后࿰…...
做盗版电影网站吗/南京关键词网站排名
为更好地从Activity跳转,并且带数据传递和关闭Activity,加上请求码与返回码得到数据。请看详细下面的例子。 让我们看一下原代码。虽然,只有代码,大家肯定看效果的。 package com.smart.activity; import android.app.Activity…...
南昌专业网站制作公司/百度sem
背景。元素的背景显示区域在内容区和内边距区,并且边框是画在背景之上的。这就是说如果边框的样式是dotted之类的,则边框空隙之间是可以看到背景的。 可以设置背景的声明有:background-color、background-image、background-position、backgr…...
网站建设 青海/seo外包公司专家
其实可以用存储过程,但想用另一种方法实现: 首先创建一个辅助表,可以设置CREATE TABLE t4 (id int(11) NOT NULL AUTO_INCREMENT,num int(11) DEFAULT NULL,PRIMARY KEY (id) )insert into t4(num) select id from xxx limit 31;(偷懒插入31条…...
南京当的网站/中国制造网网站类型
计划2015年每天写一篇文章 由于文章编辑器的效率实在太低,所以选择演示文稿导出成图片 部分内容直接使用我在曾经北京航空航天大学开设的《移动终端用户交互工程》的演示文稿,同样效率原因因而直接贴图片 提问请移步 http:/…...
12数据网站建设/竞价排名什么意思
题目描述: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个…...