0
点赞
收藏
分享

微信扫一扫

【Linux】————信号

古月无语 2024-11-13 阅读 3

 9efbcbc3d25747719da38c01b3fa9b4f.gif

                                                      作者主页:     作者主页

                                                      本篇博客专栏:Linux

                                                      创作时间 :2024年11月12日

9efbcbc3d25747719da38c01b3fa9b4f.gif

信号和信号量

首先说明这两者之间没有任何关系

信号:信号是在软件层次对中断机制的一种模拟,是一种异步通知机制,用于通知进程发生了某个特定的事件,例如当用按下Ctrl+c时,会产生一个SIGINT信号发送给当前正在运行的进程,通知他用户想要进行中断操作。信号既可以由操作系统内核发送给进程,也可以由进程发送给进程(需要一定的权限)

信号量:信号量是一种用于进程同步和互斥的机制,用于协调多个进程或者线程对共享资源的访问。它本质上就是一个计数器,用于控制同时访问共享资源的进程或线程的数量。信号量表示当前可用资源的数量。

信号

我们可以通过kill -l来查看所有的信号。

信号的处理

信号处理有三种情况:

  1. 默认动作
  2. 忽略动作
  3. 自定义处理——信号的捕捉

信号捕捉

signal

信号的产生

信号产生的方式:

  1. 通过kill命令,向指定进程发送命令
  2. 键盘可以产生信号,Ctrl+c(SIGINT),Ctrl+\(SIGQUIT)
  3. 系统调用
  4. 软件条件
  5. 异常

系统调用

kill

通过运行下面这个代码,得到这个进程的pid,然后通过我们自己写的Mykill来执行对应的信号,实现对应的操作

raise

 

这个就是我们通过raise不断给自己发送3号信号,然后signal捕捉执行

abort

执行上述代码之后,一秒之后我们的进程就结束了,这是为什么呢?

其实abort就相当于我们的6号信号,6号信号(SIGABRT)就是终止我们的进程,即使我们自定义捕捉了这个信号,也会执行一次自定义的函数之后结束,所以这个是比较特殊的一个

由软件产生信号

SIGPIPE是一种由软件条件产生的信号。下面介绍alarm函数和SIGALRM信号。

alarm

如果我们稍微改一下代码,像这样

硬件异常产生信号

运行这段代码会直接崩溃,因为这里涉及到了除零操作,这是不允许的,还有就是野指针也会出现出错,除以0会发送8号信号(SIGFPE),野指针会发送11号信号(SIGSEGV)

此时我们如果将8号或者11号信号捕捉,就会死循环打印对应的东西

Core、Term

默认下这个功能是关闭的,我们可以这样打开

指令 ulimit -a 可以查看系统中对于普通用户能使用资源对应的限制。下面可以看到core file size 大小是0,所以云服务器默认不允许我们形成core文件。

通过ulimit -c 数字 指令,这样core file选项就打开了。此时再运行程序,就有core文件了。

 我们把Makefile文件里g++带上-g选项,允许被调试。

当程序里面有除0错误时,并且有了core文件。我们gdb进行调试。 输入 core-file core 给gdb加载core文件,我们就可以直接定位到程序出错的地方。

所以core是协助我们进行debug的文件,这种操作也叫事后调试

 阻塞信号

信号相关其他常见概念

  • 实际执行信号的处理动作叫做信号递达 (Delivery)
  • 信号从产生到递达之间的状态叫做信号未决,即Pending状态
  • 进程可以选择阻塞(Block)某个信号,阻塞和有没有未决没有关系
  • 被阻塞的信号产生时将处于未决状态,知道进程接触对此信号的阻塞,才进行递达动作
  • 注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略实在递达之后可以选择的一种处理动作

在内核中表示

sigset_t 

 信号集操作函数

 sigset_t类型内部如何存储这些bit依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量

 sigprocmask

 sigpending

捕捉信号

 内核如何实现信号的捕捉

 再谈地址空间

sigaction

 volatile

可以通过gcc main.cc -01对gcc进行优化

优化后,发现按ctrl+c 程序不会结束。因为main执行流判定代码里没有对gflag进行修改,觉得不用每次都从内存拿数据,直接在第一次拿的时候,把gflag的值优化到寄存器里,从此之后,每次while检测只检测寄存器里的值。当收到信号后修改gflag的值,修改的是内存里的gflag,就导致寄存器隐藏了内存中的真实值。这是编译器过度优化导致的问题。

为了保持内存的可见性,就有了volatile关键字。

SIGCHLD信号 

wait和waitpid函数清理僵尸进程,父进程可以阻塞等待子进程结束,也可以非阻塞地查询是否有子进 程结束等待清理(也就是轮询的方式)。采用第一种方式,父进程阻塞了就不能处理自己的工作了;采用第二种方式,父进程在处理自己的工作的同时还要记得时不时地轮询一下,程序实现复杂。 

最后:

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。

2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。

3.成年人的世界,只筛选,不教育。

4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。

5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

举报

相关推荐

0 条评论