目录
一.什么是信号处理?
二.常见信号:
三.signal() 函数的使用:
2.signal()注意事项:
3.使用场景:
四.raise()函数的使用:
注意事项
五.自定义信号处理函数:
代码说明:
一.什么是信号处理?
在 C++ 中,信号处理是处理异步事件的一种机制。信号可以由操作系统或进程自身生成,常用于通知程序某些事件的发生,例如用户中断、程序错误等。了解信号处理可以帮助开发者编写更健壮和响应快速的程序。
C++ 提供了 signal()
和 raise()
函数来支持简单的信号处理机制。这种机制允许程序响应系统事件,比如错误(如除零)或用户中断(如按下 Ctrl+C)。通过 signal()
和 raise()
,我们可以自定义如何在特定信号被触发时执行自定义操作。
二.常见信号:
- 信号(Signal):信号是操作系统向进程发送的异步通知,用于表示某个事件的发生。每种信号都有一个唯一的编号。
- 信号的用途:
- 通知进程终止、挂起或继续运行。
- 捕获错误或异常情况。
- 处理用户输入(如中断)。
信号名称 | 信号编号 | 描述 |
SIGHUP | 1 | 终端挂断(Hangup) |
SIGINT | 2 | 中断信号(通常通过按下 Ctrl+C 触发) |
SIGQUIT | 3 | 退出(Quit) |
SIGILL | 4 | 非法指令(Illegal Instruction) |
SIGABRT | 6 | 程序异常终止信号 |
SIGFPE | 8 | 程序异常终止信号 |
SIGKILL | 9 | 强制终止(Kill) |
SIGSEGV | 11 | 无效内存访问信号(如访问非法地址) |
SIGPIPE | 13 | 管道破裂(Broken Pipe) |
SIGALRM | 14 | 定时器到期(Alarm Clock) |
SIGTERM | 15 | 终止请求信号 |
SIGUSR1 | 10 | 用户定义信号 1 |
SIGUSR2 | 12 | 用户定义信号 2 |
三.signal()
函数的使用:
1.signal()函数如何使用?
signal()
函数用于设置信号处理函数,以指定在特定信号到达时执行的操作。
#include <csignal>// 定义函数签名
void (*signal(int signum, void (*handler)(int)))(int);
#include <iostream>
#include <csignal>
#include <cstdlib>
using namespace std;// 自定义信号处理函数
void signalHandler(int signum) {cout << "收到信号 " << signum << ",程序即将终止。\n";// 清理并关闭// 终止程序 exit(signum);
}int main() {// 设置 SIGINT(Ctrl + C 中断)的信号处理函数signal(SIGINT, signalHandler);// 设置 SIGTERM(程序终止请求)的信号处理函数signal(SIGTERM, signalHandler);cout << "按 Ctrl+C 以发送 SIGINT 信号,或等待程序发出 SIGTERM 信号。\n";// 无限循环,保持程序运行while (1) {cout << "程序正在运行...\n";sleep(1); // 模拟程序工作,延迟1秒}return 0;
}
代码解析:
2.signal()注意事项:
- 信号处理函数的限制:信号处理函数应尽可能简单,因为它会中断程序的正常执行。应避免在信号处理函数中调用诸如
malloc
、free
或printf
等非线程安全的函数。 - 跨平台性:虽然
signal()
在不同平台上可用,但信号的行为可能不同。例如,有些信号在 Windows 上可能不支持。 - 信号默认行为:使用
SIG_DFL
恢复信号的默认处理行为,使用SIG_IGN
忽略信号。
3.使用场景:
- 资源清理:当程序被外部信号中断时,可以用信号处理函数进行资源清理操作,例如关闭文件或释放内存。
- 控制程序流程:在长时间运行的程序中,可以通过捕获特定信号来控制程序的行为,比如暂停、重启或终止。
- 错误处理:捕获
SIGFPE
或SIGSEGV
等信号可以在发生严重错误时执行特定操作,而不是让程序崩溃。
四.raise()函数的使用:
在C++中,raise()
函数是一个用来发送信号的标准库函数,定义在 <csignal>
头文件中。它的主要用途是向调用进程发送特定的信号,这可以用来控制程序的行为,比如终止程序、暂停程序等。
#include <csignal>int raise(int signum);
- 参数:
signum
:要发送的信号编号。- 返回值:成功发送信号返回 0,如果信号无法被发送,返回非零值。
#include <iostream>
#include <csignal>
#include <cstdlib>
#include <unistd.h>
using namespace std;// 信号处理函数
void signalHandler(int signum) {cout << "Caught signal: " << signum << endl;// 退出程序exit(signum);
}int main() {// 注册信号处理函数signal(SIGINT, signalHandler);signal(SIGTERM, signalHandler);cout << "Process ID: " << getpid() << endl;cout << "Press Ctrl+C to send SIGINT signal." << endl;// 无限循环,等待信号while (true) {sleep(1); // 暂停一秒}return 0;
}
注意事项
- 使用
raise()
发送信号时,通常不会产生立即的影响,因为信号的处理是异步的。信号处理程序会在程序的当前执行上下文中被调用。 - 在多线程程序中,信号会影响整个进程,而不是单个线程。
raise()
函数在调试和程序控制中非常有用,可以用来模拟信号的发送,帮助开发者更好地理解信号的处理。
五.自定义信号处理函数:
自定义信号处理函数可以用来记录日志、重启程序等高级功能。以下是另一个示例代码,处理除零错误(SIGFPE
)和无效内存访问(SIGSEGV
)信号。
#include <iostream>
#include <csignal>
#include <cstdlib>void signalHandler(int signum) {if (signum == SIGFPE) {std::cerr << "收到 SIGFPE(除零错误),请检查计算逻辑。\n";} else if (signum == SIGSEGV) {std::cerr << "收到 SIGSEGV(无效内存访问),请检查指针。\n";} else {std::cerr << "收到未知信号,编号:" << signum << "\n";}exit(signum); // 终止程序
}int main() {// 注册 SIGFPE 和 SIGSEGV 信号signal(SIGFPE, signalHandler);signal(SIGSEGV, signalHandler);std::cout << "除零错误测试:5 / 0\n";int result = 5 / 0; // 触发 SIGFPEreturn 0;
}
代码说明:
- 捕获 SIGFPE 和 SIGSEGV 信号:注册
SIGFPE
和SIGSEGV
,通过signalHandler
处理除零错误和无效内存访问。- 触发信号:当
5 / 0
执行时,产生SIGFPE
,程序进入signalHandler
。