进程组和用处
进程组:一个或多个进程的集合,进程组id是一个正整数。
组长进程:进程组id == 进程id
组长进程可以创建一个进程组,创建该进程组的进程,终止了,只要进程组有一个进程存在,进程组就存在,与组长进程是否终止无关。
进程组生存期:进程组创建到最后一个进程离开(终止或转移到另一个进程组)
一个进程可以为自己或子进程设置进程组id
作用:
子进程退出时,不管父子进程同不同一个进程组,都会发SIGCHLD信号给父进程
当父子进程同进程组时,父进程应捕捉SIGCHLD信号,对子进程资源进程回收,防止僵尸进程的产生
当父子进程不同进程组时,比如设置子进程成为了一个新的进程组,这时候子进程退出,系统也会正常回收子进程的资源,不会产生僵尸进程的
相关函数
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid); //pid = 0, pgid = 0,让当前进程成为一个进程组,并且进程组id为当前进程的pid
pid_t getpgid(pid_t pid); //pid = 0,获取当前进程的进程组id
pid_t getpgrp(void); /* POSIX.1 version */
pid_t getpgrp(pid_t pid); /* BSD version */
int setpgrp(void); /* System V version */
int setpgrp(pid_t pid, pid_t pgid); /* BSD version */
demo
父子进程同一个进程组
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>void do_sigchld(int signo)
{pid_t pid;int status;printf("signo = %d\n", signo);while((pid = waitpid(0, &status, WNOHANG)) > 0) // 0:跟调用进程同组的子进程,WNOHANG:不阻塞,立即返回{if (WIFEXITED(status))printf("child %d exit status %d\n", pid, WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("chid %d exit by signal %d\n", pid, WTERMSIG(status));}
}int main(int argc, char *argv[])
{pid_t pid;//阻塞SIGCHLD信号sigset_t set;sigemptyset(&set);sigaddset(&set, SIGCHLD);sigprocmask(SIG_BLOCK, &set, NULL);pid = fork();if (pid == 0){//in child//解除阻塞SIGCHLD信号sigprocmask(SIG_UNBLOCK, &set, NULL);//进程组printf("child pid = %d, process group id getpgid(0) = %d\n", getpid(), getpgid(0));printf("child pid = %d, process group id getpgid(getpid()) = %d\n", getpid(), getpgid(getpid()));printf("child pid = %d, process group id getpgrp() = %d\n", getpid(), getpgrp());/*setpgid(0, 0); //pid = 0, pgid = 0,让当前进程成为一个进程组,并且进程组id为当前进程的pidprintf("after setpgid(0, 0) child pid = %d, process group id getpgid(0) = %d\n", getpid(), getpgid(0));printf("after setpgid(0, 0) child pid = %d, process group id getpgid(getpid()) = %d\n", getpid(), getpgid(getpid()));printf("after setpgid(0, 0) child pid = %d, process group id getpgrp() = %d\n", getpid(), getpgrp());*/}else if (pid > 0){//in parent//先捕捉SIGCHLD信号struct sigaction act;act.sa_handler = do_sigchld;sigemptyset(&act.sa_mask);act.sa_flags = 0; //0:用sa_handler参数,SA_SIGINFO:用sa_sigaction参数sigaction(SIGCHLD, &act, NULL);//再解除阻塞SIGCHLD信号sigprocmask(SIG_UNBLOCK, &set, NULL);//进程组printf("parent pid = %d, process group id getpgid(0) = %d\n", getpid(), getpgid(0));printf("parent pid = %d, process group id getpgid(getpid()) = %d\n", getpid(), getpgid(getpid()));printf("parent pid = %d, process group id getpgrp() = %d\n", getpid(), getpgrp());sleep(1); //为了观察子进程退出时,父进程回收子进程资源}else{perror("fork");exit(1);}return 0;
}

子进程成为一个进程组时,上面的代码加入如下代码后
setpgid(0, 0); //pid = 0, pgid = 0,让当前进程成为一个进程组,并且进程组id为当前进程的pid
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>void do_sigchld(int signo)
{pid_t pid;int status;printf("signo = %d\n", signo);while((pid = waitpid(0, &status, WNOHANG)) > 0) // 0:跟调用进程同组的子进程,WNOHANG:不阻塞,立即返回{if (WIFEXITED(status))printf("child %d exit status %d\n", pid, WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("chid %d exit by signal %d\n", pid, WTERMSIG(status));}
}int main(int argc, char *argv[])
{pid_t pid;//阻塞SIGCHLD信号sigset_t set;sigemptyset(&set);sigaddset(&set, SIGCHLD);sigprocmask(SIG_BLOCK, &set, NULL);pid = fork();if (pid == 0){//in child//解除阻塞SIGCHLD信号sigprocmask(SIG_UNBLOCK, &set, NULL);//进程组printf("child pid = %d, process group id getpgid(0) = %d\n", getpid(), getpgid(0));printf("child pid = %d, process group id getpgid(getpid()) = %d\n", getpid(), getpgid(getpid()));printf("child pid = %d, process group id getpgrp() = %d\n", getpid(), getpgrp());setpgid(0, 0); //pid = 0, pgid = 0,让当前进程成为一个进程组,并且进程组id为当前进程的pidprintf("after setpgid(0, 0) child pid = %d, process group id getpgid(0) = %d\n", getpid(), getpgid(0));printf("after setpgid(0, 0) child pid = %d, process group id getpgid(getpid()) = %d\n", getpid(), getpgid(getpid()));printf("after setpgid(0, 0) child pid = %d, process group id getpgrp() = %d\n", getpid(), getpgrp());}else if (pid > 0){//in parent//先捕捉SIGCHLD信号struct sigaction act;act.sa_handler = do_sigchld;sigemptyset(&act.sa_mask);act.sa_flags = 0; //0:用sa_handler参数,SA_SIGINFO:用sa_sigaction参数sigaction(SIGCHLD, &act, NULL);//再解除阻塞SIGCHLD信号sigprocmask(SIG_UNBLOCK, &set, NULL);//进程组printf("parent pid = %d, process group id getpgid(0) = %d\n", getpid(), getpgid(0));printf("parent pid = %d, process group id getpgid(getpid()) = %d\n", getpid(), getpgid(getpid()));printf("parent pid = %d, process group id getpgrp() = %d\n", getpid(), getpgrp());sleep(1); //为了观察子进程退出时,父进程回收子进程资源}else{perror("fork");exit(1);}return 0;
}

相关文章:

进程组和用处
进程组:一个或多个进程的集合,进程组id是一个正整数。组长进程:进程组id 进程id组长进程可以创建一个进程组,创建该进程组的进程,终止了,只要进程组有一个进程存在,进程组就存在,与…...

Nacos集群+Nginx负载均衡
搭建Nacos集群 注意: 3个或3个以上Nacos节点才能构成集群。要求服务器内存分配最好大于6G以上(如果不够则需修改nacos启动脚本中的默认内存配置)根据nacos自带的mysql建库脚本建立对应数据库(/conf/nacos-mysql.sql)如果是三台服…...
TypeScript 学习之类型兼容
TypeScript 的类型兼容性是基于结构子类型的。 结构类型是一种只使用其成员来描述类型的方式。 interface Named {name: string; }class Person {name: string; }let p: Named; p new Person();// 赋值成功,因为都是结构类型,只要Person 类型的包含 Nam…...

Linux软件管理RPM
目录 前言 RPM软件管理程序:rpm RPM默认安装的路径 PRM讲解前准备工作 RPM安装(install) RPM查询(query) RPM卸载(erase) RPM升级与更新(upgrade/freshen) RPM重…...
01背包问题
背包问题的递归解决过程如下: 第一步明确思路 在解决问题之前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个…...

14_FreeRTOS二值信号量
目录 信号量的简介 队列与信号量的对比 二值信号量 二值信号量相关API函数 实验源码 信号量的简介 信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。 假设有一个人需要在停车场停车 1.首先判断停车场是否还有空车位(判断信号量是否有资源) 2.停车场正好…...

JavaScript随手笔记---轮播图(点击切换)
💌 所属专栏:【JavaScript随手笔记】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &#…...
机器人学 markdown数学公式常用语法
参考链接1 本文包含了markdown常用的数学公式,按照目录可查询选用 初始类 行内数学公式均用两个符号包裹行间数学公式均用两个符号包裹 行间数学公式均用两个符号包裹行间数学公式均用两个符号包裹,用于表示重要的、需在行间单独列出的公式 $行内数学…...
如何使用 Python 语言来编码和解码 JSON 对象
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写。 JSON 函数 使用 JSON 函数需要导入 json 库:import json。 函数 描述 json.dumps 将 Python 对象编码成 JSON 字符串 json.loads 将已编码的 JSON 字符串解码为 Pyth…...
【蓝桥云课】求正整数的约数个数
一、求正整数n的约数个数 方法一(常用算法):从1到n逐一判断其能否整除n,若能整除n即为n的约数,否则不是n的约数。 方法二:从1到n\sqrt{n}n逐一判断是否为n的约数,当n\sqrt{n}n为n的约数时,个数加1&…...
刷题记录: wannafly25 E 牛客NC19469 01串 [线段树维护动态dp]
传送门:牛客 题目描述: Bieber拥有一个长度为n的01 串,他每次会选出这个串的一个子串作为曲谱唱歌,考虑该子串从左 往右读所组成的二进制数P。 Bieber每一秒歌唱可以让P增加或减少 2 的 k次方(k由Bieber选 定),但必须…...

懂九转大肠的微软New Bing 内测申请教程
最近微软的New Bing开放内测了,网上已经有拿到内测资格的大佬们对比了ChatGPT和New Bing。对比结果是New Bing比ChatGPT更强大。来看看具体对比例子吧 1.时效性更强 ChatGPT的库比较老,跟不上时事,比如你问它九转大肠的梗,ChatG…...

WRAN翻译
基于小波的图像超分辨残差注意力网络 Wavelet-based residual attention network for image super-resolution 代码: https://github.com/xueshengke/WRANSR-keras 摘要: 图像超分辨率技术是图像处理和计算机视觉领域的一项基础技术。近年来,…...
ROS学习笔记——第二章 ROS通信机制
主要跟着[1]学习ros::Rate r(1); //错误,应改为ros::Rate r(10);[2]对Topic通信打的比方很形象,便于理解记忆。[3]有整个过程的图片,对于初学者更加友好[4]对发布者的代码注释非常好,方便进一步学习此外CMake官方文档可以查询相关…...

MacOS Pytorch 机器学习环境搭建
学习 Pytorch ,首先要搭建好环境,这里将采用 Anoconda Pytorch PyCharm 来一起构建 Pytorch 学习环境。 1. Anoconda 安装与环境创建 Anoconda 官方介绍:提供了在一台机器上执行 Python/R 数据科学和机器学习的最简单方法。 为什么最简单…...

项目——博客系统
文章目录项目优点项目创建创建相应的目录,文件,表,导入前端资源实现common工具类实现拦截器验证用户登录实现统一数据返回格式实现加盐加密类实现encrypt方法实现decrypt方法实现SessionUtil类实现注册页面实现前端代码实现后端代码实现登录页…...

PHP(14)会话技术
PHP(14)会话技术一、概念二、分类三、cookie技术1. cookie的基本使用2. cookie的生命周期3. cookie的作用范围4. cookie的跨子域5. cookie的数组数据四、session1. session原理2. session基本使用3. session配置4. 销毁session一、概念 HTTP协议是一种无…...

对JAVA 中“指针“理解
对于Java中的指针,以下典型案例会让你对指针的理解更加深刻。 首先对于: 系统自动分配对应空间储存数字 1,这个空间被变量名称b所指向即: b ——> 1 变量名称 空间 明…...

功率放大器在MEMS微结构模态测试研究中的应用
实验名称:功率放大器在MEMS微结构模态测试研究中的应用研究方向:元器件测试测试目的:随着MEMS器件在各个领域中广泛应用,对微结构进行模态测试获得其动态特性参数对微结构的设计、仿真、制造、以及质量控制和评价等方面具有十分重…...

【算法基础】字典树(Trie树)
一、Trie树原理介绍 1. 基本概念 Trie 树,也叫“字典树”。顾名思义,它是一个树形结构。它是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。【高效存储和查找字符串集合的数据结构】,存储形式如下: 2. 用数组来模拟Trie树的…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
HybridVLA——让单一LLM同时具备扩散和自回归动作预测能力:训练时既扩散也回归,但推理时则扩散
前言 如上一篇文章《dexcap升级版之DexWild》中的前言部分所说,在叠衣服的过程中,我会带着团队对比各种模型、方法、策略,毕竟针对各个场景始终寻找更优的解决方案,是我个人和我司「七月在线」的职责之一 且个人认为,…...