You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pselect调用期间触发信号时,信号处理函数如何被调用?

pselect执行期间SIGTERM信号处理函数的调用流程

pselect是具备原子性信号掩码管理的系统调用,它会一次性完成「替换进程信号掩码→等待I/O/超时→恢复原信号掩码」的操作。当SIGTERM在pselect阻塞阶段到达时,调用流程如下:

  1. 内核触发信号响应
    进程处于pselect的内核态阻塞等待时,内核收到SIGTERM信号后,会立刻暂停pselect的执行,将进程从内核态切换回用户态。

  2. 执行信号处理函数
    内核会调用你通过sigaction(或同类接口)注册的SIGTERM自定义处理函数:

    • 处理函数在用户态执行,内核会为其准备独立的栈环境。
    • 默认情况下,当前正在处理的SIGTERM信号会被自动加入进程信号掩码(同一时间不会重复触发该信号的处理),你可以通过sigaction的sa_mask字段自定义需要阻塞的信号集合。
    • 若此时有其他未被阻塞的信号到达,会在当前处理函数执行完毕后再触发对应逻辑;普通非实时信号只会保留一个待处理实例,实时信号则会排队处理。
  3. pselect的返回状态
    信号处理函数执行完成后,进程回到pselect的中断点,此时pselect会返回-1,并将全局变量errno设置为EINTR,明确标识系统调用被信号中断。

pselect与select的核心差异

普通select没有原子性的信号掩码处理逻辑,如果手动修改信号掩码后再调用select,可能在「修改掩码」和「进入select阻塞」的间隙收到信号,引发竞态条件。而pselect的信号掩码切换、等待、恢复操作是原子完成的,确保信号只会在等待阶段触发中断。

示例代码

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

void sigterm_handler(int sig) {
    write(STDOUT_FILENO, "Caught SIGTERM\n", 15);
}

int main() {
    sigset_t sigmask;
    struct sigaction sa;

    // 注册SIGTERM处理函数
    sa.sa_handler = sigterm_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGTERM, &sa, NULL);

    // 定义pselect期间的信号掩码:不阻塞任何信号,允许SIGTERM触发中断
    sigemptyset(&sigmask);

    while (1) {
        int ret = pselect(0, NULL, NULL, NULL, NULL, &sigmask);
        if (ret == -1) {
            if (errno == EINTR) {
                printf("pselect interrupted by signal\n");
            } else {
                perror("pselect failed");
                return 1;
            }
        }
    }
    return 0;
}

运行程序后执行kill -TERM <进程ID>,会先打印Caught SIGTERM,随后输出pselect interrupted by signal,程序继续进入下一轮pselect等待。


内容的提问来源于stack exchange,提问作者Harmonia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 03:07:42