本文主要是介绍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)
【功能】
促使生成信号 sig。sig 参数与 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的基础之上去搞的,切勿好高骛远哦,一步步来,加油,一起共勉
这篇关于013_C标准库函数之<signal.h>的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!