Linux进程操作(信号及信号处理--信号的基础)

信号的基础

信号基本概念

  • 概念:信号是一种进程通信的方式,又称为软件中断,一个进程一旦收到信号就会打断原来的程序执行流程来处理该信号。由于进程不知道你是否会收到信号,因此,信号通信这种进程间的通信方式是异步的。任何一个进程都可以发送信号并且接收信号。使用 killl -l 命令可以查看系统所支持的信号列表。
  • 这些信号的宏定义在 signal.h 文件中,信号编号从1开始,每个信号的具体意义用man查询。

产生信号

Linux下有五种方式产生信号:

  • 用户按下某些终端键,终端驱动程序会发送信号给前台进程;例如:ctrl+c:产生SIGINT信号,终止一个进程。
  • 硬件异常产生信号,这些条件由硬件检测到并通知内核,然后由内核向当前进程发送适当的信号。例如:被0除后产生SIGFPE信号,无效内存访问产生SIGSEGV信号(段错误)等
  • 一个进程调用kill(2)函数可以发送信号给另一个进程。
  • kill(1)命令发送信号给某个进程。
  • 内核检测到某种软件条件发生时,也可以通过信号通知进程。例如:闹钟超时产生SIGALRM。

处理信号

对于一个信号,Linux环境下的进程只有三种处理方式

  • 忽略此信号,对其置之不理;
  • 注册一个信号处理函数;
  • 执行系统默认动作,系统所使用的默认动作只有两种,终止进程或者忽略信号。

常用信号的使用方法

  • 使用 ctrl+c 或者 ctrl+/ 终止当前进程
  • 使用命令发送信号:
    例如: 在可执行程序后面加 & 使之成为后台进程,$ ./test & ,此时后台进程不能直接使用ctrl+c或者ctrl+/,因为这两个命令只能终止当前进程,因此可以根据运行后台进程后输出的进程号,使用命令发送信号终止进程:kill 7959

信号的影响

重入

  • 概念:函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入。

  • 不可重入函数:当程序运行到某一个函数的时候,可能因为硬件中断或者异常而使得在用户正在执行的代码暂时中断转而进入内核,这个时候如有一个信号需要被处理,而处理的这个信号的时候又会重新调用刚才中断的函数,如果函数内部有一个全局变量需要被操作,那么,当信号处理完成之后重新返回用户态恢复中断函数的上下文再次继续执行的时候,对同一个全局变量的操作结果可能就会发生改变而并不如我们预期的那样,这样的函数被称为不可重入函数。例如在进行链表的插入时,插入函数访问一个全局链表,有可能因为重入而造成错乱。

  • 可重入函数:相对应的,当一个执行流因为异常或者被内核切换而中断正在执行的函数而转为另外一个执行流时,当后者的执行流对同一个函数的操作并不影响前一个执行流恢复后执行函数产生的结果,我们就称这个函数为可重入函数。可重入函数只访问自己的局部变量或参数。

  • 符合以下条件之一则是不可重入的:
    1、使用了全局的数据,例如全局变量或静态变量。
    2、调用了动态方法得到内存(调用malloc函数)因为动态分配内存的方法也是以链表来管理内存分配的,这种数据也是全局作用域的。
    3、使用了标准I/O库,标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
    总结:所以,归根结底所有使用具有全局作用域的数据的函数,都是不可重入的,这种函数代码被称为非纯代码

原子操作

  • 概念:整个操作一旦开始是不会被打断的,必须直到操作结束其他代码才能得以调度运行,这就叫原子操作。
  • volatile: C语言中volatile用来修饰一个变量,表示这个变量可以被编译器之外的东西改变。编译器之内的意思是变量的值的改变是代码的作用,编译器之外的改变就是这个改变不是代码造成的,或者不是当前代码造成的,编译器在编译当前代码时无法预知。譬如在中断处理程序 isr 中更改了这个变量的值,譬如多线程中在别的线程更改了这个变量的值,譬如硬件自动更改了这个变量的值(一般这个变量是一个寄存器的值). 以上说的三种情况(中断isr中引用的变量,多线程中共用的变量,硬件会更改的变量)都是编译器在编译时无法预知的更改,此时应用使用volatile告诉编译器这个变量属于这种(可变的、易变的)情况编译器在遇到volatile修饰的变量时就不会对该变量的访问进行优化,就不会出现错误。编译器的优化在一般情况下非常好,可以帮助提升程序效率。但是在特殊情况(volatile)下,变量会被编译器想象之外的力量所改变,此时如果编译器没有意识到而去优化则就会造成优化错误,优化错误就会带来执行时错误。而且这种错误很难被发现. volatile 是程序员意识到需要 volatile 然后在定义变量时加上 volatile ,如果你遇到了应该加volatile的情况而没有加程序可能会被错误的优化。如果在不应该加 volatile 而加了的情况程序不会出错只是会降低效率。所以我们对于volatile的态度应该是:正确区分,该加的时候加不该加的时候不加,如果不能确定该不该加为了保险起见就加上
  • 原子类型 sig_atomic_t : 当把变量声明为该类型是,则会保证该变量在使用或赋值时, 无论是在32位还是64位的机器上都能保证操作是原子的, 它会根据机器的类型自动适应。

中断系统调用

信号的到来会中断进程,使得进程跳转到信号处理程序处执行,然后继续执行该进程的其他部分。如果在信号到来的时候正在执行系统调用,则该系统调用会被中断,当信号处理程序返回时,系统会重新启动系统调用。使用signal 函数加载的信号处理程序总是会在信号处理结束后重新启动被中断的系统调用;而使用sigaction函数可以设置信号处理程序返回时是否重启被中断的系统调用。如果设置不重启系统调用,这将是一个使外设的读写函数从低速设备的阻塞中解放出来的好方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值