C 标准库 - <signal.h>

简介

<signal.h> 是 C 标准库中的一个头文件,用于处理信号。

signal.h 头文件定义了一个变量类型 sig_atomic_t、两个函数调用和一些宏来处理程序执行期间报告的不同信号。

信号是一种异步通知机制,允许进程在特定事件发生时执行预定义的处理函数。

下面是一个简单的示例程序,演示如何使用 signal 函数来捕捉 SIGINT 信号(通常由 Ctrl+C 产生)。

实例

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

// 全局变量,指示程序是否应退出
volatile sig_atomic_t stop = 0;

void handle_sigint(int sig) {
    printf("Caught signal %d\n", sig);
    stop = 1; // 设置退出标志
}

int main() {
    // 将 SIGINT 信号的处理程序设置为 handle_sigint 函数
    signal(SIGINT, handle_sigint);

    while (!stop) { // 检查是否应退出
        printf("Running...\n");
        sleep(1);
    }

    printf("Exiting...\n");

    return 0;
}

以上代码中,当程序运行时,如果用户按下 Ctrl+C,会捕捉到 SIGINT 信号并调用 handle_sigint 函数,打印出信号编号。

编译执行以上代码,输出结果如下:

Running...
Running...
Running...
^CCaught signal 2
Exiting...

代码解析:

  • volatile sig_atomic_t stop = 0;:定义一个全局变量 stop,用于指示程序是否应退出。使用 volatile 关键字确保编译器不会优化掉对该变量的访问,因为它可能在信号处理程序中被修改。sig_atomic_t 类型保证了对该变量的访问是原子的。
  • handle_sigint 信号处理函数中,将 stop 设置为 1,指示程序应退出。
  • 在主循环中,检查 stop 变量的值,如果它被设置为 1,则跳出循环,结束程序。

库变量

下面是头文件 signal.h 中定义的变量类型:

序号变量 & 描述
1sig_atomic_t
这是 int 类型,在信号处理程序中作为变量使用。它是一个对象的整数类型,该对象可以作为一个原子实体访问,即使存在异步信号时,该对象可以作为一个原子实体访问。
2sigset_t
一种数据类型,用于表示信号集。

库宏

<

在 C 标准库中,SIG_ 前缀的宏与 signal 函数一起使用,用于定义和处理信号的行为。下面是常见的 SIG_ 宏及其用途:

序号宏 & 描述
1 SIG_DFL
表示信号的默认处理程序。使用此宏将信号恢复到其默认行为。
2 SIG_ERR
表示信号处理函数设置出错的返回值。
3 SIG_IGN
忽略信号。

信号类型:

常量描述
SIGABRTabort 函数产生的信号,表示异常终止
SIGALRMalarm 函数设定的定时器到期信号
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
SIGPOLLI/O 事件(取代 SIGIO)
SIGPROF定时器到期信号(由 setitimer 设置的 profiling timer)
SIGSYS非法系统调用
SIGTRAP断点或陷阱指令
SIGURG套接字紧急条件信号
SIGVTALRM虚拟时钟定时器到期信号
SIGXCPU超过 CPU 时间限制
SIGXFSZ超过文件大小限制

库函数

下面是头文件 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); 阻塞等待信号并处理。