二十七、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 ...
随机推荐
- HDU 6319 Problem A. Ascending Rating(单调队列)
要求一个区间内的最大值和每次数过去最大值更新的次数,然后求每次的这个值异或 i 的总和. 这个序列一共有n个数,前k个直接给出来,从k+1到n个数用公式计算出来. 因为要最大值,所以就要用到单调队列, ...
- CAN总线要点
前言 CAN总线的应用在现在看来越来越广泛,我厂设备从最初的ARM9与ARM7平台.期间升级过度到CortexA8与Cortex M3平台,再到现在的Cortex M4平台,围绕CAN进行了一系列产品 ...
- Zabbix-proxy安装部署
原文链接:https://www.cnblogs.com/irockcode/p/6754659.html 环境: 因为公司需要监控远程客户机,但server端无法主动连接agent端,客户端可以连接 ...
- 洛谷P3810 陌上花开 CDQ分治(三维偏序)
好,这是一道三维偏序的模板题 当然没那么简单..... 首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了: 这么好听的名字#(滑稽) 那么我们看了题面后就发现:这就是一个三维偏序.只不过ans不加 ...
- Eclipse搭建SpringBoot之HelloWorld
你的eclipse需要先安装 Spring Tool Suite™ 第一种方法(不建议,之所以贴上是因为探索的过程) 首先新建Maven工程 勾选第一个按钮,第三个是选择working set ,你可 ...
- hdu 3613"Best Reward"(Manacher算法)
传送门 题意: 国王为了犒劳立下战功的大将军Li,决定奖给Li一串项链,这个项链一共包含26中珠子"a~z",每种珠子都有 相应的价值(-100~100),当某个项链可以构成回文时 ...
- POJ 3522 Slim Span(极差最小生成树)
Slim Span Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 9546 Accepted: 5076 Descrip ...
- 使用Microsoft Toolkit 2.5 激活windows server 2012 R2与office
本人亲测可以激活windows server 2012 R2版 关于此软件介绍如下: 这是一款可以用来管理或者配置 Microsoft Office 和 Windows 的许可证(密钥)的工具,也用来 ...
- Lock与synchronized的区别(浅谈)
Lock是一个接口 synchronized是一个关键字 Lock用法: synchronized用法: lock.lock() ...
- hadoop datanode 启动出错
FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for block pool Block po ...