10.3 信号处理
2025/12/11大约 4 分钟
10.3 信号处理
- 父进程往往和子进程一样繁忙,因此不能只调用waitpid函数以等待子进程终止:父进程需要在子进程结束时收到通知,然后进行相关后续处理
- 子进程终止的识别主体是操作系统:操作系统管理进程的运行状态
- “信号”是在特定事件发生时由操作系统向进程发送的消息:子进程结束属于特定事件,可以由操作系统通过“信号”通知其父进程
- 为了响应该消息,执行与消息相关的自定义操作的过程称为“处理” 或 “信号处理”
sigaction
NAME
sigaction, rt_sigaction - examine and change a signal action
SYNOPSIS
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
The sigaction structure is defined as something like:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| signum | specifies the signal and can be any valid signal except SIGKILL and SIGSTOP. | ||
| act | If act is non-NULL, the new action for signal signum is installed from act. | ||
| oldact | If oldact is non-NULL, the previous action is saved in oldact. |
结构体sigaction中成员的含义
| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| sa_handler | SIG_DFL: default action; SIG_IGN: ignore this signal; pointer: 函数指针,指向的函数接收signum作为参数,对信号进行处理 | sa_handler specifies the action to be associated with signum | |
| sa_mask | sa_mask specifies a mask of signals which should be blocked | ||
| sa_flags | SA_NOCLDSTOP: If signum is SIGCHLD, do not receive notification when child processes stop SA_NODEFER:Do not prevent the signal from being received from within its own signal handler. | specifies a set of flags which modify the behavior of the signal. | 信号处理默认不可中断,不能嵌套(调用自身)。如果有新的信号产生,会排队,等待当前信号处理完毕然后再处理新的信号。设置SA_NODEFER后会先处理新的信号后处理旧的信号。 |
问:能不能在信号处理中产生信号?
通过man 7 signal 查看支持的信号:
Signal Value Action Comment
──────────────────────────────────────────────────────────────────────
SIGHUP 1 Term Hangup detected on controlling terminal
or death of controlling process
SIGINT 2 Term Interrupt from keyboard
SIGQUIT 3 Core Quit from keyboard
SIGILL 4 Core Illegal Instruction
SIGABRT 6 Core Abort signal from abort(3)
SIGFPE 8 Core Floating point exception
SIGKILL 9 Term Kill signal
SIGSEGV 11 Core Invalid memory reference
SIGPIPE 13 Term Broken pipe: write to pipe with no
readers
SIGALRM 14 Term Timer signal from alarm(2)
SIGTERM 15 Term Termination signal
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
SIGCHLD 20,17,18 Ign Child stopped or terminated
SIGCONT 19,18,25 Cont Continue if stopped
SIGSTOP 17,19,23 Stop Stop process
SIGTSTP 18,20,24 Stop Stop typed at terminal
SIGTTIN 21,21,26 Stop Terminal input for background process
SIGTTOU 22,22,27 Stop Terminal output for background process
SIGURG 16,23,21 Ign Urgent condition on socket (4.2BSD)
SIGVTALRM 26,26,28 Term Virtual alarm clock (4.2BSD)action描述接收信号后进程的默认行为:
| 行为 | 说明 |
|---|---|
| Term | 终止进程 |
| Core | 终止进程并核心转储 |
| Ign | 忽略该信号 |
| Cont | 继续执行 |
| Stop | 暂停 |
alarm
信号列表中有一个 SIGALRM ,在通过alarm产生的Timer 计时结束后触发该信号。
NAME
alarm - set an alarm clock for delivery of a signal
SYNOPSIS
#include <unistd.h>
unsigned int alarm(unsigned int seconds);| 参数 | 值 | 用途 | 说明 |
|---|---|---|---|
| seconds | 设定的倒计时 | 从调用alarm开始计时,到达seconds 后触发SIGALRM 信号。如果seconds 为0,所有未触发的timer 都会被取消(停止计时,不会触发SIGALRM 信号) | |
| RETURN VALUE | 获取之前设定的倒计时剩余秒数 |
新的alarm 会取消之前设定的Timer 或者说是覆盖掉(重新计时)
测试
处理通过alarm()触发的 SIGALRM 信号
实现:
void timeout(int sig)
{
if(sig == SIGALRM)
puts("time out!");
}
int main(int argc, char* argv[])
{
struct sigaction act;
act.sa_handler = timeout;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, 0);
alarm(2);
printf("sleeping for 5 seconds...\n");
sleep(5);
printf("wake up\n");
return 0;
}| 行号 | 功能 | 说明 |
|---|---|---|
| 1-5 | 定义信号处理函数 | 收到SIGALRM 时打印提示信息 |
| 12 | 将sa_mask清空 | 接收所有信号 |
| 14 | 设置信号处理的对象 | |
| 16 | 开始计时 | |
| 18 | 让进程休眠 | 休眠时间大于时钟时间 |
效果:
sleeping for 5 seconds...
time out!
wake up触发了SIGALRM信号,休眠的进程被唤醒处理信号。
其他特性测试
- 后设置的alarm 会取消前面设置的alarm
实现:
alarm(2);
alarm(1);效果:
sleeping for 5 seconds...
time out!
wake up只打印了一次time out
- seconds 为0时,any pending alarm is canceled
实现:
alarm(2);
alarm(0);效果:
sleeping for 5 seconds...
wake up没有SIGALRM信号