最近在看陈硕大大 的《Linux 多线程服务端编程:使用 muduo C++ 网络库》 ,看到里面用variadic template 和boost智能指针 实现了一个 signal/slot,现在C++11 就想利用纯C++11 实现一遍。 结果发现,只要把原来代码中boost智能指针替换为c++11 的智能指针,把陈大大自己实现的MutexLock替换为std::mutex, MutexLockGuard 替换为std::lock_guard wp(wadk_ptr<T>的简称)是槽感知信号生命的指针,在信号中的vector<weak_ptr<slot_imp>>则可以感知每个槽的生命。能感受到对方的生命,就可以执行相应操作。 signal_slot_test $(TEST):signal_slot_test.cpp $(TEST): g++ signal_slot_test.cpp -o signal_slot_test -std=c++11
通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者,这是特别有用的设计因为有些代码对某些事件是特别感兴趣的,比如删除动作。 下面,分别介绍一下三种信号的使用示例。 这个时候,就体现出信号的作用了。 一般可以监听这个信号,来记录网站异常信息。 7. appcontext_tearing_down:app上下文被销毁的信号。 Scrapy信号 Scrapy使用信号来通知事情发生。您可以在您的Scrapy项目中捕捉一些信号(使用 extension)来完成额外的工作或添加额外的功能,扩展Scrapy。 : engine_started scrapy.signals.engine_started() 当scrapy引擎启动爬取时发送该信号 该信号支持返回deferreds 当信号可能会在信号spider_opened
1718篇原创内容 公众号 这是一份来自工信部的文件,《工信部2016379号-11 微弱信号的检测方法》,发布单位:国家无线电监测中心、国家无线电频谱管理中心。 核心术语 术语 定义 信号检测 在噪声干扰中识别目标信号存在性的技术过程 微弱信号 信噪比低于0 dB、埋藏于噪声中的信号 微弱信号检测 通过特定处理方法提升信噪比,以识别有用信号的技术 微弱信号检测的三种主要方法 方法 原理 优点 适用场景 自相关检测 利用信号自身相关性 不需参考信号 自发信号监测 互相关检测 利用参考信号与目标信号相关性 抑制干扰能力强 卫星信号提取 锁定放大法 频谱搬移+低通滤波 抗窄带噪声能力强 流程: 信号预处理(滤波、混频、中放) 一路信号延迟后与原信号相乘 经积分器获得自相关函数 当噪声为零均值、非周期时,,从而可检测出有用信号 信号模型 接收信号: :有用信号 :噪声信号(假设为零均值 E5%8F%B7-11%E5%BE%AE%E5%BC%B1%E4%BF%A1%E5%8F%B7%E7%9A%84%E6%A3%80%E6%B5%8B%E6%96%B9%E6%B3%95.pdf 原文在此
: 忽略此信号 执行该信号的默认处理动作 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号 2.产生信号 2.1 通过终端按键产生信号 kill命令可以有多种写法,上面的命令还可以写成 kill -SIGSEGV 4568 或 kill -11 4568,11是信号SIGSEGV的编号。 3.阻塞信号 3.1 信号其他相关常见概念 实际执行信号的处理动作称为信号递达(Delivery) 信号从产生到递达之间的状态,称为信号未决(Pending) 进程可以选择阻塞 (Block )某个信号 ,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号 函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示该信号集的有效信号包括系统支持的所有信号 注意, 信号没有阻塞 4.捕捉信号 4.1 内核如何实现信号的捕捉 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号 由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下
一、为何需要信号量 信号量用来干嘛的呢?搜寻答案的话,很多人都会告诉你主要用于线程同步的,意思就是线程通信的。 二、信号量的实现 那么我们如何用C++来实现一个信号量呢? namespace std; 6 7 class Semaphore 8 { 9 public: 10 Semaphore(long count = 0) : count(count) {} 11 写好了信号量的接口,那我们如何使用这个信号量呢?这个就需要我们在外部写一个多线程的调用函数来调用。 <iostream> 4 using namespace std; 5 6 Semaphore sem(0); 7 8 void funA() 9 { 10 sem.wait(); 11
信号其他相关的基本概念 实际执行信号的处理动作称为 信号递达(Delivery) 信号从产生到递达之间的状态,称为 信号未决(Pending) 进程可以选择 阻塞 (Block) 某个信号。 这个位图由32个比特位组成,分别代表32个不同的信号,如果对应的比特位为1,表示该信号已经产生但尚未处理) 信号阻塞:如果目标进程阻塞了某些信号,那么这些信号会保持在未决状态,直到进程解除对这些信号的阻塞 Linux的实现:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里 信号阻塞和未决的区别 信号阻塞(Blocking):是一个开关动作,指的是阻止信号被处理,但不是阻止信号产生 ,使其中所有信号的对应 bit 清零,表示该信号集不包含任何有效信号 函数 sigfillset 初始化 set 所指向的信号集,使其中所有信号的对应 bit 置位,表示 该信号集的有效信号包括系统支持的所有信号 它可以取以下几个值之一: SIG_BLOCK:将信号集 set 中的信号添加到当前信号屏蔽字中,阻止这些信号的传 SIG_UNBLOCK: 从当前信号屏蔽字中删除信号集 set 中的信号,允许这些信号的传递
温馨提示:信号和信号量 二者之间没有任何关系 1, 信号概念 信号是 Linux 系统提供的一种向指定进程发送特定事件的方式,进程会对信号进行识别和处理。 指定发送某种信号的 kill 命令可以有多种写法,上面的命令还可以写成 kill -11 213784,11 是信号 SIGSEGV 的编号。 此时,CPU会将引起页错误的虚拟地址保存到 CR2 寄存器中,并产生一个异常,此时就会向进程发送11号信号。 例如,SIGQUIT(编号3)和 SIGSEGV(编号11)等信号的默认动作就是终止进程并生成 core dump 但当进程因某个信号而 core(终止并 核心转储,这个动作在云服务器下是被默认关掉的 SIGQUIT(编号3)和SIGSEGV(编号11):默认动作为core,即终止进程并生成core dump。
中找到 其中:1-30号信号为普通信号,31-64号信号为实时信号 具体的信号采取的动作和详细信息可查看:man 7 signal 分析: Action列即为信号的默认处理方式 Core、Term即为进程终止 指定发送某种信号的 kill 命令可以有多种写法,上面的命令还可以写成 kill -11 213784,11 是信号 SIGSEGV 的编号。 此时,CPU会将引起页错误的虚拟地址保存到 CR2 寄存器中,并产生一个异常,此时就会向进程发送11号信号。 例如,SIGQUIT(编号3)和 SIGSEGV(编号11)等信号的默认动作就是终止进程并生成 core dump 但当进程因某个信号而 core(终止并 核心转储,这个动作在云服务器下是被默认关掉的 SIGQUIT(编号3)和SIGSEGV(编号11):默认动作为core,即终止进程并生成core dump。
信号保存 信号相关的概念 信号递达:指 操作系统 将一个信号(Signal)从内核传递到目标进程 的过程。它是 信号处理机制 中的关键步骤。 信号未决:信号从产生到递达之间的状态 信号阻塞 进程或线程可以暂时屏蔽某些信号,使它们在阻塞期间不会递达和处理。一旦解除阻塞,信号会被递达并处理。 被阻塞的信号将保持未决状态,直到进程解除对此信号的阻塞,才能执行递达的动作。 注意:阻塞信号和忽略信号不同,阻塞信号表示信号没有递达,但是忽略信号表示信号已经抵达了,但是我们的处理方式是忽略处理。 它通常用于 阻塞信号、解除信号阻塞 和 检查信号 等操作。 第二个参数是新的信号集,是我们修改后的信号集,而第三个参数是旧的信号集,是修改之前的信号集,方便我们修改之后方便恢复。 信号的增删查改 上面五个函数是增删查改,第一个函数是将一个信号集置为零,第二个函数是将信号集全部设置为1,第三个函数是添加新的信号到信号集当中,第四个函数表示在信号集中删除指定信号,第五个函数是在指定信号集中查找指定信号
一、什么是信号 1. 信号的概念 信号在生活中随处可见,比如体育比赛中使用的信号枪、我给你传递一个眼神(你懂的哈哈哈),等等。 阻塞信号集:也叫信号屏蔽字,将某些信号加入集合,对他们设置屏蔽,当屏蔽某个信号后,再收到该信号,该信号的处理将推后(解除屏蔽后)。 未决信号集: 信号产生,未决信号集中描述该信号的位立刻翻转为1,表信号处于未决状态;当信号被处理对应位翻转回为0,这一时刻往往非常短暂。 其中1-31号信号称之为常规信号(也叫普通信号或标准信号),34-64称之为实时信号,驱动编程与硬件相关,这些信号名字类似。 硬件异常信号 当程序出现硬件异常会产生信号: 除0操作,浮点型错误,8号信号SIGFPE。 非法访问内存,11号信号SIGSEGV,段错误。 总线错误,7号信号SIGNUS。 3.
当信号到达时,会调用该函数来处理信号。信号处理函数的原型为 void handler(int signum),其中 signum 是信号的编号。 ③ sa_mask: 这个字段用于指定一个信号集,表示在信号处理程序执行期间应该被阻塞的信号。即,在信号处理期间,可以通过 sa_mask 阻止其他信号的处理。 它包含信号处理的详细信息,如信号处理程序、信号屏蔽集等 oldact: 指向一个 struct sigaction 结构体的指针,用于存储之前信号的处理方式。 当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止 如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。
,它向系统管理员提供了一种可以杀死任一进程的可靠方法 10 SIGUSR1 这是一个用户定义的信号,即程序员可以在程序中定义并使用该信号,该信号的默认处理动作是终止进程 11 SIGSEGV 指示进程进行了一次无效的内存访问 ptr = 10; return 0; } Segmentation fault 段错误 这是每个 C/C++ 程序猿都会遇到的问题,因为太容易触发了,出现段错误问题时,操作系统会发送 11 ,当终止进程后,需要进行 core dump,产生核心转储文件 比如:3号 SIGQUIT、4号 SIGILL、5号 SIGTRAP、6号 SIGABRT、7号 SIGBUS、8号 SIGFPE、11号 ,生成核心转储文件(前提是此功能已打开),再终止进程 但在前面的学习中,我们用过 3、6、8、11 号信号,都没有发现 核心转储 文件啊 难道是我们的环境有问题吗? ,当前系统中的核心转储文件大小为 0,即不生成核心转储文件 通过指令手动设置核心转储文件大小 ulimit -c 1024 现在可以生成核心转储文件了 就拿之前的 野指针 代码测试,因为它发送的是 11
SIGCHLD产生的条件 实际上,在子进程结束的时候,会产生一个SIGCHLD信号,信号描述如下,根据man手册可以知道,子进程结束运行,其父进程会收到SIGCHLD信号,该信号的默认处理动作是忽略。 信号停止时; 子进程处在停止态,接受到SIGCONT后唤醒时; 既然子进程在退出或暂停的时候会发送SIGCHLD信号,那么我们就可以利用该信号,捕捉该信号,并在捕捉函数中完成子进程状态的回收,这样就不用使用 ,但子进程没有继承未决信号集spending; 应该在fork之前,阻塞SIGCHLD信号,注册完捕捉函数后解除阻塞。 ; 信号的处理方式必须是捕捉 (默认动作、忽略都不可以); 中断后返回-1, 设置errno为EINTR,表示被信号中断; 可以通过修改sa_flags参数来设置被信号中断后系统调用是否重启:SA_INTERRURT sa_flags还有很多可选参数,适用于不同情况,比如:捕捉到信号后,在执行捕捉函数期间,不希望自动阻塞该信号,可将sa_flags设置为SA_NODEFER,除非sa_mask中包含该信号,等等。
阻塞信号集:也叫信号屏蔽字,将某些信号加入集合,对他们设置屏蔽,当屏蔽某个信号后,再收到该信号,该信号的处理将推后(解除屏蔽后)。 未决信号集: 信号产生,未决信号集中描述该信号的位立刻翻转为1,表信号处于未决状态;当信号被处理对应位翻转回为0,这一时刻往往非常短暂。 未决信号集就是没有被处理的信号,未决信号集实际上是一个32位数,每一位代表一个信号,当信号产生的时候,就把对应的位反转为1,如果该信号未被处理就反转回0,处理了就保持为1。 而阻塞信号集会影响到未决信号集,比如说我在阻塞信号集中将2号信号为置为1,也就是将2号信号屏蔽,那么未决信号集中2号信号对应的位就会变为1(未决状态),一直阻塞在这种状态。 阻塞信号集,就是对信号进行阻塞或屏蔽设置的一个32位信号屏蔽字,同样每一位对应一个信号,如果某一位设置为1,那么该位对应的信号将被屏蔽,该信号会被延后处理,此时如果信号产生,那么未决信号集中对应的位置1
---- 前言 信号从产生到执行,并不会被立即处理,这就意味着需要一种 “方式” 记录信号是否产生,对于 31 个普通信号来说,一个 int 整型就足以表示所有普通信号的产生信息了;信号还有可能被 “阻塞 的相关概念 1.1、概念 信号 传递过程:信号产生 -> 信号未决 -> 信号递达 信号产生(Produce):由四种不同的方式发出信号 信号未决(Pending):信号从 产生 到 执行 的中间状态 信号递达(Delivery):进程收到信号后,对信号的处理动作 在这三种过程之前,均有可能出现 信号阻塞 的情况 信号阻塞(Block):使信号传递 “停滞”,无论是否产生,都无法进行处理 信号递达后的三种处理方式 ,本文探讨的是 信号保存阶段,即 物流信息 1.3、在内核中的表示 对于传递中的信号来说,需要存在三种状态表达: 信号是否阻塞 信号是否未决 信号递达时的执行动作 在内核中,每个进程都需要维护这三张与信号状态有关的表 模拟实现了 阻塞信号 - 产生信号 - 未决信号 - 解除阻塞 - 递达信号 的全过程,最终证明 信号在产生之后是保存在 未决表 中的 ----
7.1 信号的概念 什么是信号: 信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。 信号的特点: 简单,不能携带大量信息,满足特定条件才会发生。 信号也叫软中断,有可能会有延迟。 信号的实现机制: 信号实际上是由内核发送,内核来处理收到的信号。收到信号的进程,必须对信号做出处理(忽略,捕获,默认动作都行) 信号的产生: ? 信号状态: 产生 递达:信号被捕捉并处理 未决:信号被阻塞 信号四要素: 编号、事件、名称、默认处理动作 7.2 进程处理信号行为 1、默认动作 2、忽略 3、捕捉 (后面两种处理行为就需要涉及到信号集了 //Linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。 好,看完上面这些处理函数,其实这几个函数真的就是对信号集进行操作而已,而不会对具体信号有什么动作。 别急 7.4 阻塞信号集 阻塞信号集也叫做当前进程的信号屏蔽字。
进程在收到信号后,会在合适的时候处理信号,而处理信号的动作有三种: 默认处理动作 自定义信号处理动作 忽略处理 大部分信号的默认处理动作是中断进程。 硬件异常会发送11号信号,段错误。 信号的保存 概念补充 信号处理机制 信号递达(Delivery):实际实行信号的处理动作称为信号递达。(自定义、默认、忽略) 信号未决(Pending):信号从产生到递达之间的状态称为信号未决。 当信号被阻塞时,即使该信号产生,也不会立即递达进程,而是保持在未决状态。直到进程解除对该信号的阻塞,信号才会继续执行递达的动作。 信号忽略(Ignore):忽略是在信号递达之后可选的一种处理动作。 flag 0 to 1 process quit normal 注意事项 volatile** 只保证对变量访问不被优化**,并不提供原子性,也不保护多线程间的内存可见性(在多线程场景下一般需要使用 C11
---- 前言 从信号产生到信号保存,中间经历了很多,当操作系统准备对信号进行处理时,还需要判断时机是否 “合适”,在绝大多数情况下,只有在 “合适” 的时机才能处理信号,即调用信号的执行动作。 信号没有被阻塞,直接产生,记录未决信息后,再进行处理 在这种情况下,信号是不会被立即递达的,也就无法立即处理,需要等待合适的时机 特殊情况 当信号被 阻塞 后,信号 产生 时,记录未决信息,此时信号被阻塞了 当在 内核态 完成某种任务后,需要切回 用户态,此时就可以对信号进行 检测 并 处理 了 情况1:信号被阻塞,信号产生/未产生 信号都被阻塞了,也就不需要处理信号,此时不用管,直接切回 用户态 处理 过程 图片来源:Linux进程信号 ---- 3、信号的捕捉 接下来谈谈 信号 是如何被 捕捉 的 3.1、内核如何实现信号的捕捉? 表,信号在产生之后,存储在 pending 表中 信号处理阶段:信号在 内核态 切换回 用户态 时,才会被处理 ---- 总结 以上就是本次关于 Linux进程信号【信号处理】的全部内容了,本文对信号的处理时机做了探讨
信号捕捉主要是为了防止进程意外结束,并得到异常信息,捕捉信号后可以执行我们想要的动作。 1. sa_mask 调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意:仅在处理函数被调用期间屏蔽生效,是临时性设置。实际上就是执行捕捉函数期间临时屏蔽的信号集。 信号捕捉的特性和处理 2.1 信号捕捉过程中有什么特性 在信号捕捉的时候,有如下几个特性 进程正常运行时,默认PCB中有一个信号屏蔽字假设为M,它决定了进程自动屏蔽哪些信号。 当注册了某个信号捕捉函数,在捕捉到该信号以后,就要调用该信号捕捉函数,而该函数有可能执行很长时间,在这期间所要屏蔽的信号不由M来指定,而是用sa_mask(临时屏蔽信号集)来指定,等到调用完信号处理函数 实际上是这样的,未决信号集中使用某一位的0和1来记录信号是否被处理的,所以不管这个信号被发送了几次,未决信号集对应位也只能有一个1,后续也只能处理一次,它不会记录信号屏蔽期间总共发送了几次该信号,解除屏蔽后只会处理一次
SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11 SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 (11) SIGSEGV:指示进程进行了无效的内存访问。默认动作为终止进程并使用该信号。默认动作为终止进程。 (12) SIGUSR2:这是另外一个用户定义信号,程序员可以在程序中定义并使用该信号。 如果在进程解除对某个信号的阻塞之前,这种信号发生了多次,那么如果信号被递送多次(即信号在未决信号队列里面排队),则称之为可靠信号;只被递送一次的信号称为不可靠信号。