如果需要进程捕获某个信号,并作出相应的处理,就需要注册信号处理函数(其实就是内核里需要识别信号函数,类似C语言里的include某函数库)。 处理信号就类似软中断,内核为每个进程准备了一段信号向量表,记录信号的处理机制。当某个信号发生后,内核就会调用注册的函数去处理。 信号何时来,是未知的,因此进程不可能一直等待信号来。 信号的接收不是有用户进程来完成,需要内核来代理。当用户进程P2向另一个进程P1发送信号后,内核接收到信号,将信号放置P1进程的信号队里中。 当P1进程进入内核态时,会检查信号队列,并调取相应的信号函数进行处理。 ?
选项: ① -signal: 指定发送的信号。signal就是信号(可以写信号编号也可写信号名; 若没有指定信号,那么默认发送TERM终止信号。常见信号见下表)。 ② -p:模拟发送信号。 ③ -l:指定信号的名称列表。 返回值: ''' ① 常用信号及示例 信号编号 信号名 含义 1 HUP 挂起信号。 2 INT 中断信号。 Ⅱ.通过信号名使用信号(包含SIG前缀) 可通过信号编号 或 信号名 来指定信号,其中包含带有 SIG 前缀的信号名。 xlogo & # 通过使用 & 是xlogo程序在后台运行。 ② 其它常用信号 信号编号 信号名 含义 3 QUIT 退出信号。 11 SEGV 段错误信号。 20 TSTP 终端暂停信号。 28 WINCH 窗口改变信号。 ③ 查看更多信号 如果想要查看更多的信号,使用以下命令将显示完整的信号列表。
这个时候,就体现出信号的作用了。 func2(request): models.User.objects.create(title='小男孩') return HttpResponse('创建成功') def func3( 2. before_render_template:模版渲染之前的信号。 3. request_started:模版开始渲染。 4. request_finished:模版渲染完成。 Scrapy信号 Scrapy使用信号来通知事情发生。您可以在您的Scrapy项目中捕捉一些信号(使用 extension)来完成额外的工作或添加额外的功能,扩展Scrapy。 : engine_started scrapy.signals.engine_started() 当scrapy引擎启动爬取时发送该信号 该信号支持返回deferreds 当信号可能会在信号spider_opened
执行自定义动作(快递是零食,你要送给你你的女朋友) 3. : 忽略此信号 执行该信号的默认处理动作 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号 2.产生信号 2.1 通过终端按键产生信号 3.阻塞信号 3.1 信号其他相关常见概念 实际执行信号的处理动作称为信号递达(Delivery) 信号从产生到递达之间的状态,称为信号未决(Pending) 进程可以选择阻塞 (Block )某个信号 sigaddset(&act.sa_mask, 3); act.sa_flags = 0; sigaction(2,&act,&oact); for(int if ((cid = fork()) == 0) { // child printf("child : %d\n", getpid()); sleep(3)
如果进程收到参数1对应的信号,就会执行参数2对应的方法 注意: ^\Quit 表示 kill -3,相当于从键盘输入了 Ctrl + \ 同时我们也可以对多个信号进行捕捉 信号的保存和发送理解: 进程pcb 收到什么信号,就把对应比特位上的数字变为1 发送信号:修改指定进程 pcb 中的信号的指定位图的比特位 3, 信号产生 键盘可以产生信号。 在处理函数内部,通过遍历 gfuncs 中的所有函数并调用它们,执行所有注册的任务 // 3. CR2 和 CR3 寄存器在内存管理和错误处理中扮演着重要角色 CR3 寄存器用于切换不同进程的页表 CR2 寄存器则用于存储引起页错误的虚拟地址,帮助操作系统定位和处理错误 CR2 寄存器用于存储引起页错误的线性地址 例如,SIGQUIT(编号3)和 SIGSEGV(编号11)等信号的默认动作就是终止进程并生成 core dump 但当进程因某个信号而 core(终止并 核心转储,这个动作在云服务器下是被默认关掉的
信号其他相关的基本概念 实际执行信号的处理动作称为 信号递达(Delivery) 信号从产生到递达之间的状态,称为 信号未决(Pending) 进程可以选择 阻塞 (Block) 某个信号。 ,使其中所有信号的对应 bit 清零,表示该信号集不包含任何有效信号 函数 sigfillset 初始化 set 所指向的信号集,使其中所有信号的对应 bit 置位,表示 该信号集的有效信号包括系统支持的所有信号 它可以取以下几个值之一: SIG_BLOCK:将信号集 set 中的信号添加到当前信号屏蔽字中,阻止这些信号的传 SIG_UNBLOCK: 从当前信号屏蔽字中删除信号集 set 中的信号,允许这些信号的传递 3)oldset: 指向一个 sigset_t 类型的变量,用于保存调用 sigprocmask 前的原始信号屏蔽字(如果 oldset 不为 NULL)。 pending; sigpending(&pending); // 2.1 打印 PrintPending(pending); sleep(3)
如果进程收到参数1对应的信号,就会执行参数2对应的方法 注意: ^\Quit 表示 kill -3,相当于从键盘输入了 Ctrl + \ 同时我们也可以对多个信号进行捕捉 信号的保存和发送理解: 进程pcb 收到什么信号,就把对应比特位上的数字变为1 发送信号:修改指定进程 pcb 中的信号的指定位图的比特位 3, 信号产生 键盘可以产生信号。 在处理函数内部,通过遍历 gfuncs 中的所有函数并调用它们,执行所有注册的任务 // 3. CR2 和 CR3 寄存器在内存管理和错误处理中扮演着重要角色 CR3 寄存器用于切换不同进程的页表 CR2 寄存器则用于存储引起页错误的虚拟地址,帮助操作系统定位和处理错误 CR2 寄存器用于存储引起页错误的线性地址 例如,SIGQUIT(编号3)和 SIGSEGV(编号11)等信号的默认动作就是终止进程并生成 core dump 但当进程因某个信号而 core(终止并 核心转储,这个动作在云服务器下是被默认关掉的
信号与槽的内在逻辑 信号与槽: 松耦合,发送者不需要关注接收者的接口信息 接收者执行动作是异步的 执行动作的整体效率比回调函数要低 回调函数: 强耦合,调用者和被调用者必须遵守回调接口规范(如:接口参数规范 ) 执行回调函数是同步的 执行动作的整体效率比信号槽要高 以 QPushButton 按钮点击为例 当我们点击按钮时,手指要指定的步骤是:按下按钮 --> 释放按钮 按钮对应会产生三种状态: 按钮被按下 __init__() self.setWindowTitle('My Signal&Slot Window 我的信号与槽窗口') button = QPushButton () my_signal_1 = Signal(str) # 创建一个带有1个参数的信号 my_signal_2 = Signal(str, str) # 创建一个带有2个参数的信号 信号与参数个数不匹配时的异常 当信号发送时参数个数不匹配时会抛出错误: emitter.emit_signal_1('one', 'two') 信号的重载 信号的重载在 PySide6 中并不推荐使用
周期序列 3. 3. -32:1:31; %产生64点 DFT对应的采样点频率(以零频率为中心) subplot(3,1,3);stem(fk3,abs(X6k64),'.' 对于周期信号,周期信号的频谱是离散谱,只有用整数倍周期的长度作FFT,得到的离散谱才能代表周期信号的频谱。 (3)当 N=8 时, x2 (n) 和 x3 (n)的幅频特性会相同吗?为什么? ,如图 (2a) 和 (3a) 所示 但是,当 N=16 时,x3(n) 与 x2(n) 就不满足循环移位关系了,所以如图 (2b) 和 (3b) 所示,幅频特性不同 五、实验总结 用 FFT 对信号作频谱分析是学习数字信号处理的重要内容
信号保存 信号相关的概念 信号递达:指 操作系统 将一个信号(Signal)从内核传递到目标进程 的过程。它是 信号处理机制 中的关键步骤。 信号未决:信号从产生到递达之间的状态 信号阻塞 进程或线程可以暂时屏蔽某些信号,使它们在阻塞期间不会递达和处理。一旦解除阻塞,信号会被递达并处理。 被阻塞的信号将保持未决状态,直到进程解除对此信号的阻塞,才能执行递达的动作。 注意:阻塞信号和忽略信号不同,阻塞信号表示信号没有递达,但是忽略信号表示信号已经抵达了,但是我们的处理方式是忽略处理。 它通常用于 阻塞信号、解除信号阻塞 和 检查信号 等操作。 第二个参数是新的信号集,是我们修改后的信号集,而第三个参数是旧的信号集,是修改之前的信号集,方便我们修改之后方便恢复。 信号的增删查改 上面五个函数是增删查改,第一个函数是将一个信号集置为零,第二个函数是将信号集全部设置为1,第三个函数是添加新的信号到信号集当中,第四个函数表示在信号集中删除指定信号,第五个函数是在指定信号集中查找指定信号
,该信号的默认处理动作是终止进程 3 SIGQUIT 当用户按组合键(一般采用 Ctrl + \ )时,终端驱动程序产生此信号并发送至前台进程组中的每一个进程,该信号不仅终止前台进程组,同时会产生一个 构成,一个信号对应一种动作,对于进程来说,动作无非就这几种:终止进程、暂停进程、恢复进程,3 个信号就够用了啊,为什么要搞这么多信号? ,那么信号就不能被立即处理,此时进程需要保存信号,后续再处理 3.进程可以将 多个信号 或 还未处理 的信号存储在 signal_struct 这个结构体中,具体信号编号,存储在 uint32_t signals 执行动作变成了我们注册的新动作 这足以证明 ctrl + c 就是在给前台进程发出 2 号信号,ctrl + c 失效后,可以通过 ctrl + \ 终止进程,发出的是 3 号信号(3 号信号在发出后, ,这里就不一一展示了,其实命令行中的 kill 命令就是对 kill 函数的封装,kill -信号编号 -PID 其中的参数2、3不正是 kill 函数所需要的参数吗?
iPhone信号特别差?最近很多用户向我们这样吐槽iPhone信号问题。 1.jpeg 针对这个问题,我们收集了一些果粉在论坛里提供的几种能有效改善信号问题的方法,有需要的小伙伴们可以试一下,必要的时候可以收藏喔! 1. 打开定位 手机信号不好的时候,打开定位可以提升手机信号。开启定位后系统会自动搜索离我们最近的网络基站,从而提高信号感。 设置网络选择 我们也可以通过设置不同的网络在增强信号,网络的选择根据我们使用的运营商来确定。 3. 还原网络 如果尝试了以上两种方法后信号还是一般的话,可以通过还原网络设置来解决。 操作指南:【设置】-【通用】-【还原网络设置】 3.jpg 另外两种比较常见的方法为重启手机或者开启再关闭飞行模式。
基础案例 我们先来看一个比较简单的案例:一个普通的打印数字的程序,每隔1s的时间就打印一个数字出来,我们可以使用python的signal.signal来捕获这个终止信号。 需要注意的是,如果此时不加上sys.exit(0)这个终止的操作,这个程序不会被停止,会继续运行下去,相当于只是捕获了异常终止信号但不做任何的处理。 给终止信号传入外部参数 在上面的一个案例中,仅仅只是捕获了“终止运行”的这个外部信号,但是如果更进一步的,我们想捕获到最后一个输出的数字是多少,这个时候要如何操作呢? signal_exit.py 0 1 2 3 ^C Signal Catched! The last number is: 3 可以看到,我们成功的捕获到了最后一个被输出出来的参数。
进程收到信号要无条件处理信号,并且可以选择忽略(忽略也是对信号的一种处理)、捕捉、处理信号默认的动作等。 3. (SIG T STP → signal terminal stop) Ctrl+\ :3号信号SIGQUIT,表示退出。(SIG QUIT → signal quit) 2. 硬件异常信号 当程序出现硬件异常会产生信号: 除0操作,浮点型错误,8号信号SIGFPE。 非法访问内存,11号信号SIGSEGV,段错误。 总线错误,7号信号SIGNUS。 3. 可以这么理解,如果是第一次开启定时器,返回0;如果上一次设定了alarm(5),两秒之后又设置了alarm(3),那么这个alarm()返回上一次定时器剩余的时间,也就是5-2=3秒。 0}}; setitimer(ITIMER_REAL, &temp, NULL); /*ITIMER_REAL,3秒后发送SIGALRM信号*/ while(1) {
③ sa_mask: 这个字段用于指定一个信号集,表示在信号处理程序执行期间应该被阻塞的信号。即,在信号处理期间,可以通过 sa_mask 阻止其他信号的处理。 当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止 sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, 3); sigaddset(&act.sa_mask, 4); sigaddset 函数是否可重入的关键在于函数内部是否对全局数据进行了不受保护的非原子操作,其中原子操作指的是一次完成,中间不会被打断的操作,表示操作过程是安全的 因此如果一个函数中如果对全局数据进行了原子操作,但是因为原子操作本身是不可被打断的,因此是可重入的 3. 主执行流 -- flag 未做任何修改 printf("我是正常退出的\n"); } 正常情况下的输出: 进行编译优化: 编译优化的设置:g++ -o @ ^ -Ox ( x = 0 1 2 3
在 CPU 中,存在一个 CR3 寄存器,这个 寄存器 的作用就是用来表征当前处于 用户态 还是 内核态 当寄存器中的值为 3 时:表示正在执行用户的代码,也就是处于 用户态 当寄存器中的值为 0 时: 情况3:当前信号的执行动作为 忽略 当信号执行动作为 忽略 时,不做出任何动作,直接返回 用户态 情况4:当前信号的执行动作为 用户自定义 这种情况就比较麻烦了,用户自定义的动作位于 处理 过程 图片来源:Linux进程信号 ---- 3、信号的捕捉 接下来谈谈 信号 是如何被 捕捉 的 3.1、内核如何实现信号的捕捉? ); //实时信号相关,不用管 }; 返回值:成功返回 0,失败返回 -1 并将错误码设置 参数1:待操作的信号 参数2:sigaction 结构体,具体成员如上所示 参数3:保存修改前进程的 sigaction 号信号的循环结束(10 秒),3、4、5 信号的 阻塞 状态解除,立即被 递达,进程就被干掉了 注意: 屏蔽信号集 sa_mask 中已屏蔽的信号,在 用户自定义动作 执行完成后,会自动解除 阻塞 状态
SIGCHLD产生的条件 实际上,在子进程结束的时候,会产生一个SIGCHLD信号,信号描述如下,根据man手册可以知道,子进程结束运行,其父进程会收到SIGCHLD信号,该信号的默认处理动作是忽略。 信号停止时; 子进程处在停止态,接受到SIGCONT后唤醒时; 既然子进程在退出或暂停的时候会发送SIGCHLD信号,那么我们就可以利用该信号,捕捉该信号,并在捕捉函数中完成子进程状态的回收,这样就不用使用 ,但子进程没有继承未决信号集spending; 应该在fork之前,阻塞SIGCHLD信号,注册完捕捉函数后解除阻塞。 这样做的目的是,假如在注册信号捕捉函数之前子进程就已经结束的话,信号捕捉函数就什么也捕捉不到了,会产生僵尸进程; 3. 中断系统调用 系统调用可分为两类:慢速系统调用和其他系统调用。 sa_flags还有很多可选参数,适用于不同情况,比如:捕捉到信号后,在执行捕捉函数期间,不希望自动阻塞该信号,可将sa_flags设置为SA_NODEFER,除非sa_mask中包含该信号,等等。
7.1 信号的概念 什么是信号: 信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。 信号的特点: 简单,不能携带大量信息,满足特定条件才会发生。 信号也叫软中断,有可能会有延迟。 信号的实现机制: 信号实际上是由内核发送,内核来处理收到的信号。收到信号的进程,必须对信号做出处理(忽略,捕获,默认动作都行) 信号的产生: ? 信号状态: 产生 递达:信号被捕捉并处理 未决:信号被阻塞 信号四要素: 编号、事件、名称、默认处理动作 7.2 进程处理信号行为 1、默认动作 2、忽略 3、捕捉 (后面两种处理行为就需要涉及到信号集了 sigemptyset(&act.sa_mask); sigaction(SIGALRM, &act, NULL); //setitimer 5秒之后每隔3秒来一次信号 struct itimerval myit={{3,0},{5,0}}; //这个后续章节会提到,我现在也不是很清楚 setitimer(ITIMER_REAL, &myit, NULL);//还有这个 while(1){
阻塞信号集:也叫信号屏蔽字,将某些信号加入集合,对他们设置屏蔽,当屏蔽某个信号后,再收到该信号,该信号的处理将推后(解除屏蔽后)。 未决信号集: 信号产生,未决信号集中描述该信号的位立刻翻转为1,表信号处于未决状态;当信号被处理对应位翻转回为0,这一时刻往往非常短暂。 -1)*/ int sigismember(const sigset_t *set, int signum); 3. sigprocmask函数与sigpending函数 3.1 sigprocmask ,未决信号集中对应的2、3位将置1,并阻塞信号*/ sigaddset(&mvector, SIGKILL); /*9号信号不能被阻塞,设了也没用*/ sigprocmask(SIG_BLOCK 当按键产生信号的时候,未决信号集中对应的2、3位将置1,未决信号集变为0110000000000000000000000000000。
的相关概念 1.1、概念 信号 传递过程:信号产生 -> 信号未决 -> 信号递达 信号产生(Produce):由四种不同的方式发出信号 信号未决(Pending):信号从 产生 到 执行 的中间状态 假设现在要获取第 127 个比特位 首先定位数组下标(对哪个数组操作):127 / (8 * sizeof (unsigned long int)) = 3 求余获取比特位(对哪个比特位操作):127 _val[3] |= (1 << 31) 置 0:XXX. _val[3] &= (~(1 << 31)) 所以可以仅凭 sigset_t 信号集,对 1024 个比特位进行任意操作,关于 位图 结构的实现后续介绍 ---- 2、信号集操作函数 对于 信号 的 参数3:也是一个信号集,保存进程中原来的 block 表(相当于给你操作后,反悔的机会) 这个函数就是 参数 1 比较有讲究,主打的就是一个 从 set 信号集 中获取阻塞信号相关信息,然后对进程中的