子进程信号处理

SIGCHLD 信号详解


一、信号定义与作用

SIGCHLD‌ 是 UNIX/Linux 系统中由内核向父进程发送的信号,用于通知子进程的状态变化(如终止、停止或恢复)‌。其主要作用包括:

  1. 回收子进程资源‌:避免子进程终止后成为僵尸进程(Zombie Process)占用系统资源‌。
  2. 监控子进程状态‌:父进程可响应子进程的异常退出、暂停或恢复事件‌。

二、触发条件

当子进程发生以下状态变化时,内核会向父进程发送 SIGCHLD 信号:

  1. 正常终止或异常退出‌(如调用 exit() 或被 SIGKILL 终止)‌。
  2. 被作业控制信号暂停‌(如 SIGSTOPSIGTSTP)‌。
  3. 由暂停状态恢复运行‌(收到 SIGCONT 信号)‌。

信号编号‌:17
默认行为‌:系统级忽略(不回收资源,可能导致僵尸进程)‌。


三、信号处理方式

1. ‌自定义信号处理函数

父进程需注册处理函数,通过 waitpid 回收子进程:

#include <signal.h>
#include <sys/wait.h> void handler(int sig) 
{int status;while (waitpid(-1, &status, WNOHANG) > 0); // 非阻塞回收所有终止子进程 
} int main() 
{signal(SIGCHLD, handler); // 注册处理函数 //... 创建子进程 ... 
}
  • 关键点‌:
    • 使用 WNOHANG 标志循环调用 waitpid,防止多个子进程同时退出时信号丢失‌。
    • 必须在创建子进程前注册处理函数,避免竞争条件导致信号遗漏‌。
2. ‌显式忽略信号(自动回收)
signal(SIGCHLD, SIG_IGN); // 内核自动回收子进程资源
  • 注意‌:
    • 此为 Linux 特有行为,不符合 POSIX 标准,其他 UNIX 系统可能不支持‌。
    • 子进程停止时不再发送信号(BSD 系统行为差异)‌。

四、注意事项与风险

  1. 信号不排队问题
    多个子进程同时退出可能仅触发一次 SIGCHLD,处理函数需循环调用 waitpid 直至返回错误‌。
  2. 系统调用中断
    慢速系统调用(如 read)可能被信号中断,需手动重启或检查 EINTR 错误码‌。
  3. 高并发场景优化
    服务器中频繁的子进程退出可能影响性能,可通过忽略信号或批量回收策略优化‌。

五、典型应用场景

  1. 服务端进程监控
    Web 服务器父进程捕获子进程异常退出信号,实现自动重启机制‌。
  2. 交互式 Shell 作业控制
    Shell 通过 SIGCHLD 跟踪后台进程状态(如 jobs 命令)‌。

跨系统差异提示‌:

  • BSD 系统中设置 SA_NOCLDSTOP 标志后,子进程停止时不发送信号‌。
  • Python 等语言的信号处理遵循操作系统实现,需注意接口兼容性‌。

sigprocmask函数介绍

sigprocmask 是 UNIX/Linux 系统中用于管理进程信号屏蔽字的系统调用,通过控制信号的阻塞状态实现关键代码段的保护或信号同步。以下是其核心机制与应用详解:


一、函数原型与参数

#include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • 参数说明
    • how:操作类型,可选值:
      • SIG_BLOCK:将 set 中的信号加入当前屏蔽集(阻塞)‌。
      • SIG_UNBLOCK:从当前屏蔽集中移除 set 中的信号(解除阻塞)‌。
      • SIG_SETMASK:直接替换当前屏蔽集为 set 指定的信号集‌。
    • set:指向待操作的信号集,若为 NULL 则不修改屏蔽集‌。
    • oldset:保存原屏蔽集,可为 NULL‌。
  • 返回值‌:成功返回 0,失败返回 -1 并设置 errno‌。

二、核心功能与原理

  1. 信号屏蔽机制
    • 每个进程拥有独立的信号屏蔽字(Signal Mask),决定哪些信号被临时阻塞‌。
    • 被阻塞的信号处于 ‌未决(pending)‌ 状态,直到解除阻塞后才会递送‌。
  2. 不可阻塞的信号
    • SIGKILL 和 SIGSTOP 无法被阻塞或忽略(强制终止/暂停进程)‌。

三、典型应用场景

  1. 保护临界区代码
    阻塞信号防止中断共享数据修改等关键操作‌67。
    sigset_t mask; 
    sigemptyset(&mask); 
    sigaddset(&mask, SIGINT); 
    sigprocmask(SIG_BLOCK, &mask, NULL); // 阻塞SIGINT 
    /* 临界区代码 */ 
    sigprocmask(SIG_UNBLOCK, &mask, NULL); // 恢复
  2. 多线程信号控制
    结合 pthread_sigmask 实现线程级信号屏蔽‌。
  3. 与 sigsuspend 配合
    临时修改屏蔽字并挂起进程,等待特定信号‌。

四、注意事项

  1. 信号丢失风险
    长时间阻塞可能导致非实时信号被丢弃‌。
  2. 异步信号安全
    避免在信号处理函数中调用非安全函数(如 printf)‌。
  3. 多线程环境
    sigprocmask 仅影响调用线程的屏蔽字,需使用 pthread_sigmask 控制进程级信号‌。

五、示例代码

以下代码演示阻塞 SIGINT 并恢复原屏蔽集:

#include <signal.h>
#include <stdio.h>int main() {sigset_t new_mask, old_mask;sigemptyset(&new_mask);sigaddset(&new_mask, SIGINT);// 阻塞SIGINT并保存原屏蔽集if (sigprocmask(SIG_BLOCK, &new_mask, &old_mask) == -1) {perror("sigprocmask");return 1;}printf("SIGINT blocked. Press Ctrl+C to test.\n");sleep(5); // 模拟关键操作// 恢复原屏蔽集sigprocmask(SIG_SETMASK, &old_mask, NULL);printf("SIGINT unblocked.\n");return 0;
}

逻辑流程‌:
初始屏蔽集 → SIG_BLOCK → 信号阻塞(pending)→ SIG_UNBLOCK/SIG_SETMASK → 恢复递送‌。

例:

static void
block_sigchild (void)
{sigset_t mask;int status;sigemptyset (&mask);sigaddset (&mask, SIGCHLD);if (sigprocmask (SIG_BLOCK, &mask, NULL) == -1)die_with_error ("sigprocmask");/* Reap any outstanding zombies that we may have inherited */while (waitpid (-1, &status, WNOHANG) > 0);
}

这段代码实现了对 SIGCHLD 信号的阻塞和僵尸进程清理功能,主要用于防止子进程状态变化干扰主程序执行。以下是分步解析:

  1. 信号阻塞部分

    • sigemptyset(&mask) 初始化空的信号集
    • sigaddset(&mask, SIGCHLD) 将 SIGCHLD 信号加入信号集
    • sigprocmask(SIG_BLOCK, &mask, NULL) 阻塞该信号,防止子进程退出中断主流程
    • 若阻塞失败调用 die_with_error 报错退出
  2. 僵尸进程清理部分

    • while (waitpid(-1, &status, WNOHANG) > 0) 循环非阻塞地回收所有已终止子进程
    • WNOHANG 参数确保没有僵尸进程时立即返回
    • 通过 status 参数丢弃子进程退出状态(未处理)

典型应用场景:

  • 在守护进程或服务端程序中,避免子进程退出信号干扰主事件循环
  • 防止未处理的 SIGCHLD 导致大量僵尸进程积累

注意:

  • 该实现会丢弃所有子进程退出状态,如需处理返回值需修改 waitpid 逻辑
  • 长期运行程序可能需要定期调用此函数清理新产生的僵尸进程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/915960.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF 项目设置应用程序图标和设置程序集图标

在 WPF 项目中更改生成的可执行文件&#xff08;.exe&#xff09;图标需要完成两个关键步骤&#xff1a;设置应用程序图标和设置程序集图标。以下是详细操作指南&#xff1a; 第一步&#xff1a;准备图标文件 准备一个 .ico 格式的图标文件&#xff08;必须使用 ICO 格式&…

JMeter压测黑马点评优惠券秒杀的配置及请求爆红问题的解决(详细图解)

目录 一、前言 二、优惠券秒杀压测配置 三、已配置token但是请求全部爆红的问题 四、配置JSON断言后的效果 一、前言 在学习黑马点评优惠券秒杀功能的压力测试时&#xff0c;由于老师没有任何引导而是直接开始测试&#xff0c;所以本博客记录一下JMeter压测黑马点评优惠券秒…

Nginx 运维实战: 什么是反向代理,如何配置?

在互联网的庞大架构中&#xff0c;Nginx 作为一款高性能的 Web 服务器和反向代理服务器&#xff0c;发挥着至关重要的作用。其中&#xff0c;反向代理功能更是 Nginx 被广泛应用的核心原因之一。本文将深入探讨什么是反向代理&#xff0c;以及如何在 Nginx 中进行反向代理的配置…

短视第三套多功能主题3.0二开模板苹果CMS插件重构版

这款短视第三套多功能主题二开模板苹果CMS插件重构版源码&#xff0c;基于市面上现有的二开版本进行的重制修正更新。目前已经完美适配新版 4049 以上的苹果Cms系统&#xff0c;无需担心因系统版本问题导致的不兼容情况。​主题插件重构后支持一键启动插件自动安装模板&#xf…

详解力扣高频SQL50题之1148. 文章浏览 I【入门】

传送门&#xff1a;1148. 文章浏览 I 题目 Views 表&#xff1a; ---------------------- | Column Name | Type | ---------------------- | article_id | int | | author_id | int | | viewer_id | int | | view_date | date | ---------------------- 此表可能会存在重复…

内外网互传文件 安全、可控、便捷的跨网数据交换

内外网互传文件 安全、可控、便捷的跨网数据交换破解企业数字化痛点&#xff0c;重新定义文件传输标准在数字化转型浪潮中&#xff0c;企业面临着前所未有的挑战&#xff1a;内网系统需要严密防护&#xff0c;外网协作又要高效便民。如何在网络安全与业务效率之间找到完美平衡&…

性能监控装饰器-python

看项目时&#xff0c;发现一个性能监控装饰器&#xff0c;感觉挺有意思的。于是借鉴了他的思路&#xff0c;自己重新写了我认为更简洁的代码。作用&#xff1a;可以放在类上和方法上&#xff0c;如果放在类上&#xff0c;则监控所有方法。根据设置的阈值&#xff0c;判断方法执…

qt常用控件-05

文章目录qt常用控件-05LineEditTextEditcombo box结语很高兴和大家见面&#xff0c;给生活加点impetus&#xff01;&#xff01;开启今天的编程之路&#xff01;&#xff01; 今天我们进一步c11中常见的新增表达 作者&#xff1a;٩( ‘ω’ )و260 我的专栏&#xff1a;qt&am…

Python进阶知识之pandas库

目录 一、Series&#xff1a;一维带标签的数组 二、DataFrame&#xff1a;二维表格型数据结构 三、Series 的核心操作 四、 DataFrame 的核心操作 五、 索引的特殊用法 六、 loc 与 iloc&#xff1a;DataFrame 的高级查询 七、综合案例 一、Series&#xff1a;一维带标签…

【GIT】基础知识及基本应用

很高兴为您详细介绍Git的相关知识。Git是一个分布式版本控制系统&#xff0c;常用于软件开发中的代码管理和协作。以下是关于Git的一些基础知识&#xff1a;1. 安装和配置安装&#xff1a;Windows&#xff1a;可以从GitHub下载适用于Windows的安装包。MacOS&#xff1a;可以通过…

Maven Scope标签:解锁Java项目依赖管理的秘密武器

一、Maven 与依赖管理简介在 Java 项目开发的庞大体系中&#xff0c;Maven 堪称基石般的存在&#xff0c;发挥着极为关键的作用。它遵循 “约定优于配置” 的理念&#xff0c;让项目的构建过程变得规范有序、结构化且具备良好的重复性 。比如&#xff0c;它强制执行标准的项目结…

IP43半加固笔记本L156H

IP43半加固笔记本L156H 产品特性&#xff1a;● 标配Intel I7-7700HQ 4核8线程处理器 ● 操作系统支持Windows7/10 64bit / Li n u x ● DDR4 16G 高速内存 zui高支持64G ● 全高清显示面板15.6寸&#xff0c;1920X1080 ● 内置海德射频模块SMA接口 ● 工作温度&#xff1a;…

ZooKeeper 是什么?

ZooKeeper 是一个分布式协调服务&#xff0c;由 Apache 基金会开发&#xff0c;专为分布式系统设计。它提供了高可用、高性能、一致性的核心服务&#xff0c;帮助分布式应用解决诸如配置管理、命名服务、分布式锁、集群协调等问题。ZooKeeper 的核心特点&#xff1a;简单易用&a…

Java学习第六十三部分——K8s

目录 &#x1f4eb; 一、关键概述 &#x1f50d; ​​二、定义起源​​ &#x1f680; ​​三、核心特点​​ &#x1f3d7;️ ​​四、核心组件​​ &#x1f9e9; ​​五、资源对象​​ ⚡ ​​六、应用场景​​ &#x1f9f1; ​​七、Java与K8s &#x1f6e0;️ ​…

【自用】JavaSE--阶段测试

考试题目第一题&#xff08;10分&#xff09;需求目前有100名囚犯&#xff0c;每个囚犯的编号是1-200之间的随机数。现在要求依次随机生成100名囚犯的编号&#xff08;要求这些囚犯的编号是不能重复的&#xff09;&#xff0c;然后让他们依次站成一排。(注&#xff1a;位置是从…

Vulnhub Matrix-Breakout-2-Morpheus靶机攻略

1.下载靶机 靶机下载地址&#xff1a;https://download.vulnhub.com/matrix-breakout/matrix-breakout-2-morpheus.ova 下载后使用VM打开&#xff0c;后续选择安装地址开启就算是下载好了 2.主机发现 查看网络适配器模式&#xff08;NET模式&#xff09;&#xff0c;找到NET…

OpenCV —— 绘制图形

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

RHCE(4)

主&#xff1a;从&#xff1a;

网络安全作业三

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>用户登录</title><link rel"style…

深入理解 ThreadLocal:从原理到最佳实践

&#x1f4dd; 前言&#xff1a;为什么你需要了解 ThreadLocal&#xff1f;在多线程并发编程中&#xff0c;线程安全始终是一个绕不开的话题。我们常常需要为每个线程维护一份独立的上下文数据&#xff0c;例如用户信息、事务 ID、日志追踪 ID 等。这些数据不能被多个线程共享&…