C 标准库 – signal.h

关键要点

  • <signal.h> 是 C 标准库中的头文件,用于处理信号,研究表明它支持异步通知机制。
  • 它定义了 sig_atomic_t 类型、多种信号常量(如 SIGINTSIGTERM)和函数(如 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 不能被捕获或忽略,研究建议在设计时充分考虑这些限制。
  • 信号的顺序:信号的处理顺序不确定,程序应设计为不依赖于信号的处理顺序,以避免不可预测的行为。
  • 信号的重入:信号处理程序应设计为重入安全,以避免在信号处理期间再次接收相同信号导致的问题。

资源与参考

以下是相关资源的链接,提供更详细的中文讲解:

这些资源涵盖了 <signal.h> 的所有方面,包括函数的详细使用和注意事项。

总结

<signal.h> 是 C 语言中处理信号的核心工具,提供了丰富的函数和宏,支持信号的定义、处理和管理。它的功能在错误处理、用户输入响应和进程间通信中非常有用。通过上述内容,用户可以全面了解 <signal.h> 的功能,并通过示例代码快速上手。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注