365网站建设,ae做动画教程网站,如何建立单位微信公众号,17网站一起做网店类似的信号我们将从信号产生#xff0c;信号的保存#xff0c;信号处理分别进行讲解~
至少大思路是这样。开始之前还要进行一些基础知识的铺垫。 目录 从生活中提炼一些结论#xff1a;信号概念的一些储备#xff1a;信号产生#xff1a;一、kill指令#xff1a;二、键盘组合键…信号我们将从信号产生信号的保存信号处理分别进行讲解~
至少大思路是这样。开始之前还要进行一些基础知识的铺垫。 目录 从生活中提炼一些结论信号概念的一些储备信号产生一、kill指令二、键盘组合键三、系统调用四、软件条件五、异常 从生活中提炼一些结论
a. 信号在生活中随处可以产生------比如红绿灯天空打雷… b. 我可以识别识别这些信号-----虽然我可能在课堂中但是并不妨碍我认识 c. 当信号产生了该如何进行处理------比如我知道红灯亮了不能走绿灯亮了可以走 d. 我在做别的更重要的事对到来的信号暂时不做处理 我上段阶段中的“我”换为“进程”“生活”换为“OS”就是我们的信号了 但是仅仅有了上边的概念还不够还要进行一些补充 对于a信号的产生与进程是异步的 对于b,c说明进程可以识别并处理信号 对于d其一进程需要记住这个事。其二进程需要再合适的时候在去处理。
信号概念的一些储备
这里会涉及到我们刚刚提到的信号产生信号保存信号处理先分别涉及一点点在详细的进行解释。
异步 那么怎样理解异步异步就像是在课堂上老师让一个学生去拿快递如果老师在等待那个学生过来就是同步不等待直接进行讲课就是异步。 你拿你的快递我将我的课互不干扰
信号 是linux提供的一种向指定进程发送发送特定实践的方式。 我们基于以上的两点先来看一看到底信号是个啥 使用kill -l命令即可看到linux中的全部信号。 1到31号是普通信号超过31是实时信号我们不进行考虑1 我们写个如下程序并对其发送9号信号相信我们目前都用过的一个信号相对来说也是最熟悉的 发现果然被kill了 上图其实就是一个进程对信号进行处理的一个例子我们就以这个为切入点进行信号处理的渗透。
信号处理常用的有3种方式 a. 默认动作 b. 忽略动作 c. 自定义动作
对于a进程处理信号都是默认的通常包括终止暂停忽略… 下图中框起来的就是默认动作Core与Term其实都代表终止但具体的区别我们等等在谈。
对于b忽略就是忽略的意思
对于c那么就不得不提我们的signal函数了 这是一个对信号进行捕捉的系统调用捕捉后收到该信号就会去执行自定义的操作。
我们来用代码具体实践一下 执行指令 现象没有执行默认动作而是执行我的自定义动作并且ctrl c也终止不了 结论 我们handler函数中的函数其实就是发送的信号2号信号就是ctrl c strl c就是向进程发送2号新号
那么此刻我想问几个问题 1 如果没有产生信号呢 2 我们捕捉更多的信号呢
对于问题一没有产生新的信号就代表是正常运行 对于问题二我们进行捕捉多个信号进行测试。
对2 3 4进行测试仍然是和我们预期一致收到信号会执行我们的自定义函数但真的是这样吗对于这点我们待会有验证。
其实此时我们就可以总结出两个信号产生的方式
kill组合键 我们如何理解信号的发送与保存 这里只是浅度的认识一下毕竟我们也说了这只是一些对产生保存处理的一些预备知识。
先来看保存 详细细心的小伙伴以经发现我们的信号是从1开始31结束没有0。为什么呢
这里就到回到进程了进程是task_struct结构体结构体中有成员变量在这些变量中有一个uint32_t 的类型变量名字不准确却能反映出关键 这个无符号整形有0000 0000 0000 0000 0000 0000 0000 000032个零。 我们使用位图对这32位比特位进行利用
当发送信号1时就将1号比特位置为1 0000 0000 0000 0000 0000 0000 0000 0010 发送2时就将2号比特位置为1 0000 0000 0000 0000 0000 0000 0000 0100… 以此类推。
发送 我们修改指定的PCB中的信号位图即可 将0置为1所以发信号貌似叫做写信号更合适。
但是这里有个要注意的点OS是软硬件资源的管理者PCB是一个内核数据结构理所应当的只有OS有权利进行写入所以OS才有资格进行修改。
信号产生
这里在强调一下我们现在刚刚结束预备知识的部分。
我们已经得出了两点结论。
一、kill指令 二、键盘组合键
ctrlc。 ctrlc是我们最常用的但不是唯一一个组合键还有一个ctrl\也是让进程终止的组合键。 三、系统调用
说到系统调用那必然要提到一个接口 其实看到这个命令我们大概也能想到kill指令其实也就是由这个调用来的。 那我们来模拟一下kill指令。
进行测试果然如此。 再来看另外一个系统调用raise。 本质上是对kill的封装对调用此函数的进程发送你指定的信号。 现象被捕捉后就去执行我们的自定义代码随后死循环-和我们预期一样。 再来看一个系统调用 abort 与raise是一样的不过这个是指定发送6号信号。 但是要注意一点虽然允许捕捉但仍然会终止是我们常用的3种处理方式例外。
现在我们有两个问题 一把信号全部捕捉会怎样 二如何理解发送
对于1我打个for循环全部捕捉即可~ 当我们尝试9时就会发现虽然在代码中捕捉了但是实际上是不允许的不然如果你真的全捕捉那岂不是反了天了哈哈。 但实际上除了9还有别的指令也和9一样不允许捕捉。
对于二只是为了再次强调是OS进行发送信号修改PCB中的位图。 四、软件条件
一个很抽象的名词。
我们来举一个例子。 在管道阶段我们知道当读端关闭写端继续写入就会被OS发送SIGPIPE信号。 那么和软件条件有什么关系的 管道的产生条件是与struct file内核缓冲区等具有非常紧密的关系的他们都是软件当当读端关闭写端继续写入就会不满足软件条件最终导致13号信号的发送。
这时候我们就有需要认识一个新的函数了 闹钟函数。 我们先来看一看这函数
现象
这实际上是14号新号。 现象果然收到了14号新号 现在有了以上的基础我们要谈论3个子问题 a. 理解一下IO成本 b. 理解alarm c. alarm的返回值
对于a我们其实很好验证 稍微修改一下代码即可观察到现象 11w到9亿足以看到IO的速度是非常慢的。
对于b 在理解之前我们要先说另一个话题我们肯定经历过手机断电还几天或者电脑但是开机之后仍然可以保持标准的时间这是由于我们的电子设备内置了一个纽扣电池帮助我们计时。 而闹钟可以准时提醒我们是根据一个时间戳的东西。
我们理解一个事物往往需要一个切入角度而这个角度往往都是先描述在组织我们有那么多进程每个进程都可能有一个闹钟那么就需要先描述则个闹钟。 这个结构体内有各种各样的描述闹钟的变量。
那我们选择什么进行组织呢 当我们要寻找一个没有超时的闹钟时只要找到最后一个超时的后一个就可以了 我们可以采用有序链表但这样太慢了所以我们最终选择堆每次pop时就是当前的最小堆观察是否超时即可
对于3我们在设一个闹钟进行观察。 当把sleep改为4时 由此我们可以得出结论返回值是闹钟剩余的时间。
而我们alarm0本质上就是取消闹钟因为它实际上没有什么意义。
那我们设置一个alarm(2)也是取消上一个闹钟在重新设置一个。
注意闹钟默认是触发一次的 虽然设置了多个但是只会触发一个因为每次设置都是对上一次的闹钟的取消。
那我们如何设置一个闹钟一直触发 答在捕捉函数里在设置一个即可也叫做常设闹钟。
五、异常
关于异常我们一定遇到过真的是太经典了…