signal() -函数的详细使用说明
一、函数概述
signal()
函数用于设置特定信号的处理方式。它允许程序在接收到特定信号时执行自定义的处理函数,或者采用默认的处理方式,也可以选择忽略该信号。
二、函数原型
void (*signal(int sig, void (*func)(int)))(int);
这个函数接收两个参数,返回一个函数指针。
三、参数说明
sig
:- 这是一个整数参数,表示要处理的信号编号。常见的信号有
SIGINT
(通常由 Ctrl+C 产生)、SIGTERM
(通常用于请求程序终止)等。不同的操作系统可能支持不同的信号集。
- 这是一个整数参数,表示要处理的信号编号。常见的信号有
func
:- 这是一个函数指针参数,指向一个信号处理函数。该函数接收一个整数参数(即信号编号),无返回值。
func
可以取以下几种值:SIG_DFL
:表示使用默认的信号处理方式。不同的信号有不同的默认行为,例如,对于SIGINT
,默认行为通常是终止程序。SIG_IGN
:表示忽略该信号。即当程序接收到该信号时,不进行任何特殊处理。- 一个用户自定义的函数指针,指向一个信号处理函数。这个函数将在接收到指定信号时被调用。
四、使用步骤
-
包含头文件:
- 在使用
signal()
函数之前,需要包含<signal.h>
头文件。
- 在使用
-
定义信号处理函数:
- 如果要使用自定义的信号处理函数,需要先定义一个函数,其参数为整数类型(表示信号编号),无返回值。例如:
void signal_handler(int signum) {// 在这里编写信号处理的代码 }
-
调用
signal()
函数:- 在程序中合适的位置调用
signal()
函数,设置特定信号的处理方式。例如,设置对SIGINT
信号的处理为调用自定义的signal_handler
函数:
signal(SIGINT, signal_handler);
- 在程序中合适的位置调用
五、注意事项
- 信号处理函数应该尽量简单快速,避免执行复杂的操作或长时间的阻塞操作,因为信号可能在任何时候中断程序的执行。如果信号处理函数执行时间过长,可能会影响程序的响应性。
- 信号处理可能会被其他信号中断,所以在信号处理函数中要考虑到这种情况。例如,如果在处理一个信号时,又接收到了另一个信号,可能需要采取适当的措施来确保正确的处理顺序。
- 不同的操作系统对信号的处理可能会有所不同,所以在跨平台开发时需要注意兼容性问题。
- 一旦设置了信号处理函数,它将在程序的整个生命周期内有效,除非再次调用
signal()
函数来改变信号的处理方式。
六、示例代码
以下是一个完整的示例代码,展示了如何使用signal()
函数来处理SIGINT
信号:
#include <stdio.h>
#include <signal.h>/*** @brief 异常信号中断*/
DT_PRIVATE void signal_handler(int signal)
{DT_ERR("!!!!!request reboot signal:%d\r\n", signal);sync();sleep(5);dt_reboot();
}/*** @brief 异常信号处理初始化*/
DT_PUBLIC void signal_init(void)
{signal(SIGPIPE, SIG_IGN); /* 13 一个对端已经关闭的socket调用两次write, 第二次将会生成SIGPIPE信号, 该信号默认结束进程. */signal(SIGINT, signal_handler); /* 2 来自键盘的中断信号 */signal(SIGABRT, signal_handler); /* 6 程序的异常终止,如调用 abort */signal(SIGBUS, signal_handler); /* 7 总线错误(内存访问错误) */signal(SIGSEGV, signal_handler); /* 11 段非法错误(非法访问内存),如空指针*/signal(SIGTERM, signal_handler); /* 15 发送到程序的终止请求 */
}
在 C 语言中,常见的信号及其默认行为如下:
一、SIGINT(中断信号)
- 产生方式:通常由用户在终端按下 Ctrl+C 产生。
- 默认行为:终止程序。当程序接收到这个信号时,通常会立即停止运行,并进行一些清理工作(如果有必要)后退出。
二、SIGTERM(终止信号)
- 产生方式:可以通过命令行工具(如 kill 命令)发送给程序,也可能由操作系统在某些情况下发送。
- 默认行为:终止程序。与 SIGINT 类似,SIGTERM 也是请求程序终止,但它通常比 SIGINT 更“礼貌”,允许程序有机会进行一些清理工作后再退出。
三、SIGSEGV(段错误信号)
- 产生方式:当程序试图访问非法的内存地址(如访问未分配的内存、访问已释放的内存、越界访问等)时产生。
- 默认行为:终止程序并产生核心转储文件(core dump)。核心转储文件包含了程序在崩溃时的内存状态等信息,可以用于调试。
四、SIGABRT(异常终止信号)
- 产生方式:可以通过调用
abort()
函数产生。 - 默认行为:终止程序并产生核心转储文件。这个信号通常用于表示程序出现了严重的错误,无法继续运行。
五、SIGFPE(算术异常信号)
- 产生方式:当程序进行非法的算术运算时产生,例如除以零、浮点数溢出等。
- 默认行为:终止程序并产生核心转储文件。
六、SIGHUP(挂起信号)
- 产生方式:当终端关闭或者与终端的连接丢失时,控制进程(通常是一个守护进程)会收到这个信号。
- 默认行为:如果程序没有对这个信号进行特殊处理,通常会终止。但对于守护进程,通常会重新读取配置文件、重新初始化等操作,以确保在终端关闭后仍能正常运行。
七、SIGPIPE(管道破裂信号)
- 产生方式:当一个进程向一个没有读端的管道写入数据时产生。
- 默认行为:终止程序。如果程序没有处理这个信号,写入操作会失败,并返回错误码 -1,同时触发 SIGPIPE 信号,导致程序终止。
这些信号在不同的操作系统上可能会有一些细微的差别,但总体上它们的行为是相似的。在编写程序时,可以根据需要使用 signal()
函数或其他信号处理机制来改变这些信号的默认行为,以实现更灵活的程序控制和错误处理。