二十七、Linux 进程与信号---进程组和组长进程
27.1 进程组
27.1.1 进程组介绍
- 进程组为一个或多个进程的集合
- 进程组可以接受同一终端的各种信号,同一个信号发送进程组等于发送给组中的所有进程
- 每个进程组有唯一的进程组 ID
- 进程组的消亡要等到组中所有的进程结束
- 进程组的消亡:kill 发送信号给进程组
- kill -9 -进程组号
27.1.2 进程组 ID 获取--- getpgrp 和 getpgid
(1)getpgrp --- 获取调用进程的进程组ID
#include <unistd.h>
pid_t getpgrp(void);
- 函数说明
- getpgrp()用来取得目前进程所属的组识别码。此函数相当于调用 getpgid(0);
- 返回值
- 返回目前进程所属的组识别码。
(2)getpgid --- 获取 pid 所在进程组的 ID
#include <unistd.h>
pid_t getpgid( pid_t pid);
- 函数说明
- getpgid()用来取得参数 pid 指定进程所属的组识别码。如果参数 pid 为0,则会取得目前进程的组识别码。
- 返回值
- 执行成功则返回组识别码,如果有错误则返回 -1 ,错误原因存于 errno 中。
- 错误代码
- ESRCH 找不到符合参数 pid 指定的进程。
- getpgid(getpid()) 获取指定进程的进程组
- getpgid(0) 获取当前进程的进程组
27.2 组长进程
27.2.1 概念
- 每个进程组可以有个组长进程,组长进程的ID就是进程组的ID
- 组长进程可以创建进程组以及该组中的进程
- 进程组的创建从第一个进程(组长进程)加入开始
- 进程组的组号取第一个加入组的进程(组长进程)编号
27.2.2 设置进程组 ID--- setpgid(创建进程组或将指定进程加入到指定的进程组中)
#include <unistd.h>
int setpgid(pid_t pid,pid_t pgid);
- 函数说明
- setpgid() 将参数 pid 指定进程所属的组 ID 设为参数 pgid 指定的组 ID。如果参数 pid 为 0 ,则会用来设置目前进程的组识别码,如果参数 pgid 为0,则会以目前进程的进程 ID 来取代。
- 函数功能:将进程加入到指定的进程组中, pid 为进程号, pgid 为组号
- 返回值
- 执行成功则返回组 ID,如果有错误则返回-1,错误原因存于 errno 中。
- 错误代码
- EINVAL 参数 pgid 小于0。
- EPERM 进程权限不足,无法完成调用。
- ESRCH 找不到符合参数 pid 指定的进程。
27.3 例子
27.3.1 构建进程扇组
构建一个进程扇,要求每两个进程为一个进程组,如下所示

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main(void)
{ //创建进程组,组长进程为父进程
setpgid(getpid(), getpid()); /* 组1 */
// 或 pid_t group1 = getpgid(0);
pid_t group1 = getpgid(getpid());
pid_t group2; int i = ;
pid_t pid; for(; i < ; i++) {
pid = fork();
if(pid < ) {
perror("fork error`");
exit();
} else if(pid > ) {//父进程
//父进程中执行和子进程相同的操作
if(i == ) {
//要注意fork 在父进程中返回的是子进程的 pid
setpgid(pid, group1);
} //第二个子进程作为组长进程,要创建进程组
if(i == ) {
setpgid(pid, pid);
group2 = getpgid(pid);
} if(i == ) {
//第三个子进程加入到 group2
setpgid(pid, group2);
}
} else {//子进程
//将第一个子进程加入到 group1
if(i == ) {
setpgid(getpid(), group1);
} //第二个子进程作为组长进程,要创建进程组
if(i == ){
setpgid(getpid(), getpid());
group2 = getpgid(getpid());
} if(i == ) {
setpgid(getpid(), group2);
} //因为是进程扇,每一个子进程要退出循环
//父进程继续循环 fork
break;
}
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); //防止僵尸进程产生
for(i = ; i < ; i++) {
wait();
} exit();
}
编译运行:

27.3.2 构建进程链组

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main()
{
//创建进程组1,父进程为组长进程
setpgid(getpid(), getpid());
pid_t group1 = getpgid(getpid()); pid_t pid;
int i = ;
for(;i < ; i++) {
pid = fork();
if(pid < ) {
perror("fork error");
exit();
} else if(pid > ) {
if(i == ) {
//创建进程组2,第一个子进程作为组长进程
setpgid(pid, pid);
} if(i == ) {
//将第二个子进程加入到 group1中
setpgid(pid, group1);
} // 在进程链中,父进程操作完退出循环
break;
} else if(pid == ) { if(i == ) {
//创建进程组2,第一个子进程作为组长进程
setpgid(getpid(), getpid());
} if(i == ) {
//将第二个子进程加入到 group1中
setpgid(getpid(), group1);
}
}
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); //防止僵尸进程产生
for(i = ; i < ; i++) {
wait();
} return ;
}
编译运行:

27.3.3 进程组删除
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main(void)
{
//创建进程组,父进程作为组长进程
setpgid(getpid(), getpid()); pid_t pid = fork();
if(pid < ){
perror("fork error");
exit();
} else if(pid > ) {
//将子进程加入到父进程所在的组
setpgid(pid, getpgid(getpid()));
} else {
//将子进程加入到父进程所在的组
setpgid(getpid(), getpgid(getppid()));
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); pause();//进程暂停,等待信号 return ;
}
编译运行:
(1)杀掉进程组


(2)杀掉父进程


杀掉父进程后,子进程依然存在,只不过变成了孤儿进程,并被2323进程所领养
(3)杀掉子进程


子进程变为了僵尸进程,子进程被杀死,但是父进程并没有回收子进程。
杀掉父进程:

僵尸进程被回收
27.3.4 子进程不加入父进程组中
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h> int main(void)
{
//创建进程组,父进程作为组长进程
setpgid(getpid(), getpid()); pid_t pid = fork();
if(pid < ){
perror("fork error");
exit();
} else if(pid > ) {
//将子进程加入到父进程所在的组
setpgid(pid, getpgid(getpid()));
} else {
//将子进程加入到父进程所在的组
//setpgid(getpid(), getpgid(getppid()));
} printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid()); pause();//进程暂停,等待信号 return ;
}
编译运行:


没有将子进程加入到组中,依然将子进程加入到父进程组了。
注意:从 shell 上启动一个父进程,然后从父进程上创建若干个子进程,默认情况下都加入到父进程所在的组中,组号就是父进程的 PID,组长就为父进程。
二十七、Linux 进程与信号---进程组和组长进程的更多相关文章
- 二十八、Linux 进程与信号---前台进程组
28.1 介绍 28.1.1 概念 自动接受终端信号的组称为前台进程组 在终端通过 ctrl + c 等动作产生的信号首先被前台进程组接受 在 shell 启动的若干个进程组默认是父进程所在的组为前台 ...
- (二十七)Linux的inode的理解
一.inode是什么? 理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统 ...
- linux 下信号处理命令trap && linux下各种信号的意义
1.用途说明 trap是一个shell内建命令,它用来在脚本中指定信号如何处理.比如,按Ctrl+C会使脚本终止执行,实际上系统发送了SIGINT信号给脚本进程,SIGINT信号的默认处理方式就是退出 ...
- 第9章 Linux进程和信号超详细分析
9.1 进程简单说明 进程是一个非常复杂的概念,涉及的内容也非常非常多.在这一小节所列出内容,已经是我极度简化后的内容了,应该尽可能都理解下来,我觉得这些理论比如何使用命令来查看状态更重要,而且不明白 ...
- Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存
Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...
- 三十一、Linux 进程与信号——SIGCHLD 信号、kill和raise函数以及alarm函数
31.1 SIGCHLD 信号 子进程状态发生变化(子进程结束)产生该信号,父进程需要使用 wait 调用来等待子进程结束并回收它. 避免僵尸进程 #include <stdio.h> # ...
- Linux/UNIX之信号(1)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/walkerkalr/article/details/24462723 信号(1) 信号是软件中断.每 ...
- 25 Linux中的信号
Linux中的信号 信号是进程在运行过程中,由自身产生或由进程外部发过来的消息(事件).每个信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD.SIGINT等,它们在系统头文件中定义,也可以通 ...
- Linux 两组信号对比(关闭和停止进程信号)
之前看信号的时候,没有太注意不同信号的对比.今天再次看到的时候,突然感觉对一些信号,非常相似,乃至非常容易混淆.今天周末就抽空总结一下. 一.关闭进程信号 常见的4中关闭进程信号是SIGKILL,SI ...
随机推荐
- CF1106E Lunar New Year and Red Envelopes
比赛时看到这题懵逼了,比完赛仔细一想是个很简单的dp = = 由于题目限制,可以发现\(B\)取红包的策略是唯一的,可以用优先队列预处理出\(B\)在第\(i\)秒可以拿到的红包的收益\(w_i\)和 ...
- UVALive - 4225(贪心)
题目链接:https://vjudge.net/contest/244167#problem/F 题目: Given any integer base b ≥ 2, it is well known ...
- 小白眼中的AI之~Numpy基础
周末码一文,明天见矩阵- 其实Numpy之类的单讲特别没意思,但不稍微说下后面说实际应用又不行,所以大家就练练手吧 代码裤子: https://github.com/lotapp/BaseCode ...
- A1146. Topological Order
This is a problem given in the Graduate Entrance Exam in 2018: Which of the following is NOT a topol ...
- Ubuntu的 g++ gcc版本升降级
更改gcc默认版本(gcc版本降级/升级) ### 以降级到gcc-6为例 >* sudo apt install gcc-6 g++-6 >* sudo update-alternati ...
- IDEA或者WebStorm关闭JS文件的黄色提示
这个编译器虽然好用,但是友好的提醒(语法校验)太多啦 解决: 在右下角有个小人儿 然后更改提示级别
- codeforces 540E"Infinite Inversions"
传送门 题意: 给你一个无限大的整数序列 p = {1, 2, 3, ...}: 有 n 次操作,每次操作交换第 ai 个数和第 aj 个数: 求序列中逆序对的个数: 题解: 考虑交换完后的序列,存 ...
- Unable to find ‘struts.multipart.saveDir’ Struts2上传文件错误的解决方法
Unable to find ‘struts.multipart.saveDir’ Struts2上传文件错误的解决方法 在使用struts2的项目中上传文件的时候出现了一个这样的错误: 2011-7 ...
- springboot1.5升级2.0后遇到的问题
https://blog.csdn.net/zhiquanzhou/article/details/80566630
- (贪心 模拟?) codeVs1098 均分纸牌
题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N.每堆上有若干张,但纸牌总数必为 N 的倍数.可以在任一堆上取若于张纸牌,然后移动. 移牌规则为:在编号为 1 堆上取的纸 ...