013_C标准库函数之<signal.h>

头文件<signal.h>中提供了一些用于处理程序运行期间所引发的异常条件的功能,如处理来源于外部的中断信号或程序执行期间出现的错误等事件。

用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?
同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中的进程捕获到这个信号然后作出一定的操作并最终被终止。

信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动。通常信号是由一个错误产生的。
但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获

以上是我觉得说的还不错的关于信号的诠释,当然了,如果要刨根问底的话,那这些描述就太简单了,但是我们的主要目标是使用signal函数并操作信号,关于信号产生的背景这里不做过多探讨,有兴趣的朋友可以自问度娘,下来我们直入主题:

首先,我们这里着重介绍一下signal函数

void (*signal(int sig, void (*handler)(int)))(int);

这个函数看起来非常复杂,其实剖析开看,是这样的:里面是signal(int sig, void (*handle)(int)),就是一个signal函数,第一个入参为一个int类型的sig,第二个入参为void (int)类型的函数指针(关于函数指针和指针函数不懂的,可以参考我前面的文章:000_函数指针和指针函数?-CSDN博客),其实就是准备捕获的信号的参数由sig给出,接收到的指定信号后要调用的函数由参数handle给出,接下来再看外面的函数:我们把signal看作一个整体T,外面的函数形式就是void (*T)(int);该函数返回一个与handle相同类型的指针,指向先前指定信号处理函数的函数指针(请仔细品味这句话)

注意信号处理函数的原型必须为void func(int)因为函数指针定义是void (*handle)(int);

其次,我们再看看信号表:

我们可以看到有64个信号,这里我们不一一说明,只是说一下比较常用的信号值及其含义:

SIG_ 宏与 signal 函数一起使用来定义信号的功能。

宏 & 描述
SIG_DFL
默认的信号处理程序。
SIG_ERR
表示一个信号错误。
SIG_IGN
忽视信号。

SIG 宏用于表示以下各种条件的信号码:

宏 & 描述
SIGABRT
程序异常终止。
SIGFPE
算术运算出错,如除数为 0 或溢出。
SIGILL
非法函数映象,如非法指令。
SIGINT
中断信号,如 ctrl-C。
SIGSEGV
非法访问存储器,如访问不存在的内存单元。
SIGTERM
发送给本程序的终止请求信号。

【函数1:signal 】


【格式】

void (*signal(int sig, void (*handler)(int)))(int);

【功能】

该函数设置一个函数来处理信号,即信号处理程序。

signal()用于确定以后当信号sig出现时的处理方法。如果handler的值是SIG_DFL,那么就采用实现定义的缺省行为;如果handler的值是SIG_IGN,那么就忽略该信号;否则,调用handler所指向的函数(参数为信号类型)。有效的信号包括:

SIGABRT异常终止,如调用abort()。
SIGFPE算术运算出错,如除数为0或溢出。
SIGILL非法函数映象,如非法指令。
SIGINT交互式信号,如中断。
SIGSEGV非法访问存储器,如访问不存在的内存单元。
SIGTERM发送给本程序的终止请求信号。

signal()返回信号sig原来的的handler;如果出错,则返回SIG_ERR。

当随后出现信号sig时,就中断正在执行的操作,转而执行信号处理函数(*handler)(sig)。如果从信号处理程序中返回,则从中断的位置继续执行。

信号的初始状态由实现定义。

【入参】

int sig:信号,比如SIGINT,SIGKILL等

void (*handler)(int)):函数指针原型,就是void (int)函数

【返回值】

void(*)(int);一个函数指针类型的返回值

【test_code】

直接调用:

挂钩调用:

创建类型对象调用:

以上都是调用的方法,其实都大同小异,不过我还是建议使用最后一个方法比较好一些

【总结】

signal函数的的入参就是信号,函数指针,所以可以理解此函数就是捕捉到相应的信号后,然后直接跳到函数指针处对信号进行进一步的处理,那么处理完后会不会继续回来处理程序呢?从我们的案例当中可以看到是直接结束了,因为我们捕捉的是"ctrl+c"信号:退出程序,我试了其他几个信号,也不行,捕捉到信号后,直接到信号处理函数运行,运行完后直接退出,这个到底是不继续回来处理函数?还是说就直接终止了呢?还需要探究,我尚不能给出定论,有知道的大牛可以麻烦告知我下,小弟在这里谢过了^-^

【函数2:raise 】


【格式】

int raise(int sig)

【功能】

促使生成信号 sigsig 参数与 SIG 宏兼容

【入参】

  • sig -- 要发送的信号码。下面是一些重要的标准信号常量:
信号
SIGABRT(Signal Abort) 程序异常终止。
SIGFPE(Signal Floating-Point Exception) 算术运算出错,如除数为 0 或溢出(不一定是浮点运算)。
SIGILL(Signal Illegal Instruction) 非法函数映象,如非法指令,通常是由于代码中的某个变体或者尝试执行数据导致的。
SIGINT(Signal Interrupt) 中断信号,如 ctrl-C,通常由用户生成。
SIGSEGV(Signal Segmentation Violation) 非法访问存储器,如访问不存在的内存单元。
SIGTERM(Signal Terminate) 发送给本程序的终止请求信号。

【返回值】

如果成功该函数返回零,否则返回非零

【test_code】

发送SIGINT

发送SIGTERM

【总结】

raise是发送一个信号给当前进程,需要用signal函数去捕获,然后将捕获到的信号用函数指针callfptr处理,但是,如果是终止或者异常终止等信号请求,则实际直接回终止当前进程的运行,并不会再去回调函数指针

关于信号的应用及扩展,在Linux中有大量的描述,以及sigaction等功能强大的函数,这个有兴趣的可以去看看,后面我们也会在Liunx C模块中去讲解这些,当然了,本人还是觉得先把C的这些搞清楚,因为linux C是在C的基础之上去搞的,切勿好高骛远哦,一步步来,加油,一起共勉

  • 26
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值