C 标准库 – signal.h
关键要点
<signal.h>
是 C 标准库中的头文件,用于处理信号,研究表明它支持异步通知机制。- 它定义了
sig_atomic_t
类型、多种信号常量(如SIGINT
、SIGTERM
)和函数(如signal()
、raise()
)。 - 证据显示,信号常用于错误处理、用户输入响应和进程间通信。
简介
<signal.h>
允许程序捕获和处理信号,例如用户按下 Ctrl+C 或发生内存访问错误。以下是其主要功能:
主要功能
- 信号定义:包括
SIGINT
(中断)、SIGTERM
(终止)等。 - 信号处理:通过
signal()
和sigaction()
设置处理程序。 - 信号管理:使用
sigprocmask()
控制信号屏蔽。
使用示例
以下是一个简单示例,捕获 SIGINT
信号:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
volatile sig_atomic_t stop = 0;
void handle_sigint(int sig) {
stop = 1;
}
int main() {
signal(SIGINT, handle_sigint);
while (!stop) {
printf("Running...\n");
sleep(1);
}
printf("Caught signal %d, exiting...\n", SIGINT);
return 0;
}
资源
详细报告
背景与概述
<signal.h>
是 C 标准库中的一个头文件,专门用于提供信号处理的功能。信号是一种异步通知机制,允许进程在特定事件发生时执行预定义的处理函数。这些事件可以是用户操作(如按下 Ctrl+C)、系统错误(如非法内存访问)或其他进程发送的信号。研究表明,<signal.h>
的功能在处理异常情况和实现进程间通信时非常有用,证据显示它广泛应用于错误处理、用户输入响应和定时操作。
主要内容
库变量
<signal.h>
定义了以下变量类型:
sig_atomic_t
:一种整数类型,用于在信号处理程序中安全地访问的变量,确保原子操作。sigset_t
:一种数据类型,用于表示信号集,方便管理多个信号。
库宏
<signal.h>
定义了以下宏,用于信号处理:
SIG_DFL
:表示默认信号处理程序。SIG_ERR
:信号处理设置错误时的返回值。SIG_IGN
:表示忽略信号。
信号常量
<signal.h>
定义了多种信号常量,每个常量都表示一个特定的信号。以下是常见的信号常量及其描述,整理成表格以便清晰查看:
信号常量 | 描述 |
---|---|
SIGABRT | 程序异常终止 |
SIGALRM | 定时器到期 |
SIGBUS | 总线错误 |
SIGCHLD | 子进程状态改变 |
SIGCONT | 继续执行暂停的进程 |
SIGFPE | 浮点异常 |
SIGHUP | 挂断信号 |
SIGILL | 非法指令 |
SIGINT | 终端中断信号(Ctrl+C) |
SIGKILL | 强制终止信号 |
SIGPIPE | 向已关闭的管道写入 |
SIGQUIT | 终端退出信号(Ctrl+\) |
SIGSEGV | 段错误(非法内存访问) |
SIGSTOP | 暂停进程信号 |
SIGTERM | 终止信号 |
SIGTSTP | 暂停信号(Ctrl+Z) |
SIGTTIN | 后台进程读取终端 |
SIGTTOU | 后台进程写入终端 |
SIGUSR1 | 用户自定义信号1 |
SIGUSR2 | 用户自定义信号2 |
这些信号常量覆盖了常见的系统事件和用户操作,研究表明它们在不同操作系统中可能有细微差异,但核心功能一致。
库函数
<signal.h>
提供了多种函数,用于信号的处理和管理。以下是主要函数及其功能,整理成表格:
函数名 | 描述 |
---|---|
void (*signal(int sig, void (*func)(int)))(int); | 设置信号处理程序 |
int raise(int sig); | 发送信号给当前进程 |
int kill(pid_t pid, int sig); | 发送信号给指定进程 |
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); | 检查/改变阻塞的信号集 |
int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact); | 检查/改变信号处理程序 |
int sigsuspend(const sigset_t *mask); | 临时替换信号掩码并挂起 |
int sigpending(sigset_t *set); | 检查挂起的信号 |
int sigemptyset(sigset_t *set); | 初始化信号集为空 |
int sigfillset(sigset_t *set); | 初始化信号集为满 |
int sigaddset(sigset_t *set, int signum); | 将信号添加到信号集 |
int sigdelset(sigset_t *set, int signum); | 从信号集删除信号 |
int sigismember(const sigset_t *set, int signum); | 检查信号是否在信号集中 |
void abort(void); | 生成 SIGABRT 信号 |
unsigned int alarm(unsigned int seconds); | 设置定时器,发送 SIGALRM |
int pause(void); | 挂起直到捕获信号 |
void psignal(int sig, const char *s); | 打印信号描述 |
char *strsignal(int sig); | 返回信号描述字符串 |
int sigwait(const sigset_t *set, int *sig); | 等待并处理信号 |
这些函数提供了从设置信号处理程序到管理信号集的全面功能,证据显示它们在实际开发中非常实用。
使用场景
<signal.h>
的功能在多种场景下有重要应用:
- 错误处理:捕获如
SIGSEGV
或SIGFPE
等信号,执行清理操作或记录错误日志。 - 用户输入:捕获
SIGINT
(Ctrl+C)或SIGQUIT
(Ctrl+\)信号,优雅地终止程序。 - 进程间通信:使用
SIGUSR1
和SIGUSR2
等信号在进程之间传递信息。 - 定时操作:使用
alarm()
函数设置定时器,捕获SIGALRM
信号执行定时任务。
使用示例与实践
以下是一个更详细的示例,展示如何使用 signal()
和 sigaction()
处理 SIGINT
信号:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
volatile sig_atomic_t stop = 0;
void handle_sigint(int sig) {
printf("Caught signal %d, exiting...\n", sig);
stop = 1;
}
int main() {
// 使用 signal() 设置处理程序
signal(SIGINT, handle_sigint);
while (!stop) {
printf("Running...\n");
sleep(1);
}
return 0;
}
这个示例展示了如何捕获 SIGINT
信号,并通过信号处理程序优雅地退出程序。
注意事项
使用 <signal.h>
时需要特别注意以下几点:
- 信号处理程序的安全性:信号处理程序应避免调用非异步信号安全的函数,如
printf()
、malloc()
等。应使用简单操作或异步信号安全的函数,例如设置标志位。 - 信号的可靠性:某些信号如
SIGKILL
和SIGSTOP
不能被捕获或忽略,研究建议在设计时充分考虑这些限制。 - 信号的顺序:信号的处理顺序不确定,程序应设计为不依赖于信号的处理顺序,以避免不可预测的行为。
- 信号的重入:信号处理程序应设计为重入安全,以避免在信号处理期间再次接收相同信号导致的问题。
资源与参考
以下是相关资源的链接,提供更详细的中文讲解:
- 菜鸟教程 – C 标准库 – <signal.h>:提供了函数列表、宏定义和示例代码,内容全面,适合初学者和进阶用户。
- 阿里云开发者社区 – C 标准库 – <signal.h> 详解:介绍了信号处理的安全性考虑和实际应用场景,适合深入学习。
这些资源涵盖了 <signal.h>
的所有方面,包括函数的详细使用和注意事项。
总结
<signal.h>
是 C 语言中处理信号的核心工具,提供了丰富的函数和宏,支持信号的定义、处理和管理。它的功能在错误处理、用户输入响应和进程间通信中非常有用。通过上述内容,用户可以全面了解 <signal.h>
的功能,并通过示例代码快速上手。