在Linux中简单实现回收子进程
学习到wait函数了,这个函数的作用是用来回收进程。一般来说,正常退出的进程是不需要我们来专门回收的。但是进程有这两种:孤儿进程和僵尸进程。
孤儿进程:
通俗点说就是父进程先于子进程死亡。此时子进程就成为孤儿进程。这时候子进程的父进程就是init进程了。这个过程(父进程死亡后子进程的父进程变为init)称为init进程领养孤儿进程。
僵尸进程
进程终止,但是父进程并未进行回收操作。子进程的残留资源(PCB)存在于内核中,成为僵尸进程。就是儿子死了,但是父亲不收尸。
这里要注重理解的是:僵尸进程实际上是结束的进程。所以,我们能用kill命令结束它么?不能!结束一个已经结束的进程。怎么能行呢?
请看下列代码:
#include
<cstdio>
#include
<stdlib.h>
#include
<unistd.h>
int p = 111;
//pid_t fork(void);//在父进程中返回子进程的id,在子进程返回0(没有子进程了嘛,因为)。
int main(int
argc, char*argv[])//有用户指定创建多少个子进程
{
printf("hello from Create_N_subprocesses!\n");
if (argc < 2)
{
printf("Too few parameters\n");
exit(1);
}
int i, n = atoi(argv[1]);
for (i = 0; i < n; i++)
{
if (0 == fork())//父进程中返回的不是0,继续执行for循环;在子进程中返回0,for循环结束。
{
break;
}
}
//基本上每个父子进程是同时进行。所以睡眠时间依次递增。
sleep(i);
if (i < n)//父进程不能算在里面
{
p++;//这里改变p的值
printf("I am the %d process.\n p = %d\n", i + 1, p);//这里的每个p都一样,哪怕每次p都会自增
}
else
{
printf("my father process \n p = %d\n", p);//但是这里还是会输出111
}
/*
p用来验证父子之间可以用静态变量传递消息么?
答案是不可以,因为date段是独立的。
父子之间遵循读时共享,写是独立的原则。
*/
return 0;
}
这是一段用于创建N个子进程的程序代码。并且验证父子进程之间能够进行资源共享的资源共享方式是:读时共享写时独立。这些都不是重点。重点是,这个程序执行后会产生N个僵尸进程。为什么?因为我们没有进行回收。怎么回收?用wait()函数。
wait函数:该函数有三个功能:
1.阻塞等待子进程退出 (如果该子进程没有死亡,父进程阻塞,不做其他的事。)
2.回收子进程残留资源
3.获取子进程结束状态(退出原因)。
原型:pid_t wait(int *status);
返回值:成功:清理掉的子进程ID;失败:-1 (没有子进程)
需要注意的是:回收进程的工作是由当前进程的父进程来做。调用一次wait函数只会回收一个进程,若是多个进程死亡,wait函数只会回收最先死亡的那个进程。
上代码:
#include
<stdlib.h>
#include
<stdio.h>
#include
<unistd.h>
#include
<sys/types.h>
#include
<sys/wait.h>
int main()
{
int status;
int i = 0;
pid_t pid_1, pid_2;
for (; i != 1; i++)
{
pid_1 = fork();
if (!pid_1)
{
break;
}
}
if (i < 1)
{
sleep(5);
printf("I am the %d child.my ID is %d .\n", i + 1, getpid());
}
else
{
pid_2 = wait(&status);
if (-1 == pid_2)
{
perror("wait precess ");
exit(1);
}
printf("Recovery of the %d process is successful.It is ID %d .\n", i, pid_2);
if (WIFEXITED(status))
{
printf("Normal exit of process, Exit status : %d .\n", WEXITSTATUS(status));
}
else
if (WIFSIGNALED(status))
{
printf("The program exits with abnormal signal, signal value : %d.\n", WTERMSIG(status));
}
printf("I am is father.\n");
}
//printf("hello from Recycle_child_process!\n");
return 0;
}
我fork了一个子进程,并让它休眠5s。注意我的wait函数是在父进程分支中调用的,这里涉及到几个宏函数:
WIFEXITED(status) 为非0 → 进程正常结束
WEXITSTATUS(status) 如上宏为真,使用此宏 → 获取进程退出状态 (exit的参数)
WIFSIGNALED(status) 为非0 → 进程异常终止
WTERMSIG(status) 如上宏为真,使用此宏 → 取得使进程终止的那个信号的编号。
这样,程序会输出:
I am the 1 child.my ID is 6024 .
Recovery of the 1 process is successful.It is ID 6024 .
Normal exit of process,Exit status:0 .
I am is father.
ID应该是不会一样的。
程序显示该子进程是正常退出的,返回值为0;我们可以改动这个返回值:用return 语句
if (i < 1)
{
sleep(5);
printf("I am the %d child.my ID is %d .\n", i + 1, getpid());
return 1314520;
}
那么程序的输出就应该是:
I am the 1 child.my ID is 6024 .
Recovery of the 1 process is successful.It is ID 6024 .
Normal exit of process,Exit status: .
I am is father.
那我们怎么让子进程异常退出?毕竟平常也很少遇到。我们可以人为的营造环境,段错误知道吧?浮点异常知道吧?不知道可以百度或谷歌。
我们来编写一个程序:
#include
<stdio.h>
int main(void)
{
int i = 5 / 0;//浮点异常
char *p = "love dandan";
p[2] = 69;
return 0;
}
编译并命名为a.out。然后我们修改程序为:
if (i < 1)
{
execl(" / home / lovedan / projects / Recycle_child_process / bin / x64 / Debug / a.out", "a.out", NULL);//第一个参数一定是绝对路径。相信你知道execl函数
/*sleep(5);
printf("I am the %d child.my ID is %d .\n", i + 1, getpid());*/
}
这时候,程序的输出。。。。输出结果我丢失了,也不想在去重新弄了。反正吧,他会输出子进程被成功回收,但是子进程是异常退出。提示浮点异常,value值是8(即:SIGFPE)。将in i=5/0;注释掉之后在编译它,重新运行另外一个程序输出结果又会不一样。会提示我们子进程因为段错误而退出。
大概就这些吧,后面还有一个waitpid函数。后面在来介绍吧。
来更新一下:循环回收多个子进程:
上面的示例是指创建回收一个子进程,若是我们创建多个,该如何回收呢?用循环!
for (; i != 10; i++)
{
pid_1 = fork();
if (!pid_1)
{
break;
}
}
if (i < 10)
{
sleep(i);
printf("I am the %d child.my ID is %d .\n", i + 1, getpid());
}
else
{
sleep(i);
while (pid_2 = wait(&status) != -1)//循环回收进程
{
printf("Recovery of the %d process is successful.It is ID %d .\n", i, pid_2);
if (WIFEXITED(status))
{
printf("Normal exit of process, Exit status : %d .\n", WEXITSTATUS(status));
}
else
if (WIFSIGNALED(status))
{
printf("The program exits with abnormal signal, signal value : %d.\n", WTERMSIG(status));
}
printf("I am is father.\n");
}
if (-1 == pid_2)
{
perror("wait precess ");
exit(1);
}
}
我就只是贴了我修改的代码。其实变动很少,就是加个循环控制而已,这个程序的输出是:
I am the 1 child.my ID is 1225 .
I am the 2 child.my ID is 1226 .
I am the 3 child.my ID is 1227 .
I am the 4 child.my ID is 1228 .
I am the 5 child.my ID is 1229 .
I am the 6 child.my ID is 1230 .
I am the 7 child.my ID is 1231 .
I am the 8 child.my ID is 1232 .
I am the 9 child.my ID is 1233 .
I am the 10 child.my ID is 1234 .
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
Recovery of the 10 process is successful.It is ID 1 .
Normal exit of process,Exit status:0 .
I am is father.
有没有发现回收的ID全为1?因为子进程先于父进程结束啊,是正常的结束,返回值为0;如果想要测试异常结束,请自行营造环境。
在Linux中简单实现回收子进程的更多相关文章
- LINUX中简单的字符命令
1. ls 查看目录中的内容 -a 查看隐藏文件 -l 显示文件的详细信息 -d 显示目录属性 -h 人性化显示文件大小 -i 显示ID号 2. 目录操作 创建目录 mkdir [-p](递归) di ...
- 用 set follow-fork-mode child即可。这是一个 gdb 命令,其目的是告诉 gdb 在目标应用调用fork之后接着调试子进程而不是父进程,因为在 Linux 中fork系统调用成功会返回两次,一次在父进程,一次在子进程
GDB的那些奇淫技巧 evilpan 收录于 Security 2020-09-13 约 5433 字 预计阅读 11 分钟 709 次阅读 gdb也用了好几年了,虽然称不上骨灰级玩家,但 ...
- Linux中vim的简单配置
本文主要分享Linux中vim的简单配置 ★配置文件的位置 在目录/etc.下面,有个名为vimrc的文件,这就是系统中公共的vim配置文件,对所有用户都开放.而在每个用户的主目录下,都可以自 ...
- Linux 中 Vi 编辑器的简单操作
Linux 中 Vi 编辑器的简单操作 Vi 编辑器一共有3种模式:命名模式(默认),尾行模式,编辑模式.3种模式彼此需要切换. 一.进入 Vi 编辑器的的命令 vi filename //打开或新 ...
- [软件测试]Linux环境中简单清爽的Google Test (GTest)测试环境搭建(初级使用)
本文将介绍单元测试工具google test(GTEST)在linux操作系统中测试环境的搭建方法.本文属于google test使用的基础教程.在linux中使用google test之前,需要对如 ...
- Linux中DHCP服务器的简单配置
我安装了两台linux系统,一个作为服务器,一个客户端 两个都有3个网卡, 后两个网卡聚合为zhi一个网卡:Linux 网卡聚合 两台电脑都一样. 那么如何为这个聚合网卡进行DHCP的分配呢? 1.由 ...
- Linux中DHCP服务器的简单配置(转)
我安装了两台linux系统,一个作为服务器,一个客户端 两个都有3个网卡, 后两个网卡聚合为zhi一个网卡:Linux 网卡聚合 两台电脑都一样. 那么如何为这个聚合网卡进行DHCP的分配呢? 1.由 ...
- Linux 的简单命令以及在idea中配置码云
Linux 的简单命令: ls(list)功能:列出目录内容 cd(change directory)功能:切换目录 touch 1.txt 在当前目录创建一个文件1.txt clear:清除屏幕 p ...
- linux中几个简单的系统命令(还有一些其他杂项命令)
linux中几个简单的系统命令,其他命令接触到了在补充. 1.ps命令:(process status),提供对进程的一次性查看.以及执行ps命令时那个时刻的进程信息 格式:ps[参数] -e 此参数 ...
随机推荐
- junit中线程需要注意的问题
Junit主线程执行完毕后,就会结束进程,不关注是否有其他线程在运行.当Junit运行完毕后,如果其他线程还没有执行完毕,那么不会再执行. 使用CountDownLatch,保证启动的线程运行结束后, ...
- Tom与Jerry谁先死?
有如下问题:Tom的攻击力为113,血量为688,Jerry的攻击力为112,血量为691.每一个回合他们各攻击对方一次,请问谁先死? 这是一个简单的“人狗大战问题”,我们只要利用类的继承,在原有的基 ...
- MaidSafe区块链项目白皮书解读
MaidSafe.net宣布项目SAFE到社区 1. 介绍 现有的互联网基础设施越来越难以应付超过24亿互联网用户的需求,这个数字在2017年预计将增长到36亿.今天的架构中,中央中介(服务器)存储并 ...
- [UE4]使用name slot制作带背景的容器
name slot相当于asp.net模板中的content模板. 可以往“Name Slot”里面拖放控件,如果没有“Name Slot”就不能给“BgPanel”拖放任何控件
- Mongodb集群搭建之 Sharding+ Replica Sets集群架构(2)
参考http://blog.51cto.com/kaliarch/2047358 一.概述 1.1 背景 为解决mongodb在replica set每个从节点上面的数据库均是对数据库的全量拷贝,从节 ...
- a++ 与 ++a 的运算
var a=5: b=a++和b=++a的区别: 前者是先赋值,再自加,即b=a:a=a+1: //结果b=5,a=6 后者是先自加,再赋值,即a=a+1;b=a; //结果a=6,b=6
- Delphi7 中文汉字转网址格式 Utf8编码转换(淘宝搜索中文转网址)
function HttpEncode(S:AnsiString):string; var P:^Byte; I:Cardinal; begin Result:=''; P:=@S[1 ...
- C# webbrowser遍历网页元素
//不引用其他单元 foreach(HtmlElement ele in WB1.Document.All) { if(ele.I ...
- python 实现排序算法(二)-合并排序(递归法)
#!/usr/bin/env python2 # -*- coding: utf-8 -*- """ Created on Tue Nov 21 22:28:09 201 ...
- Java - 27 Java 集合框架
Java 集合框架 早在Java 2中之前,Java就提供了特设类.比如:Dictionary, Vector, Stack, 和Properties这些类用来存储和操作对象组. 虽然这些类都非常有用 ...