场景

在程序中遇到耗时较长的操作(如等待用户响应,连接remote server),通常会想到创建 Child process 去处理。在Perl 中 使用fork()

## fork a child process
die "$@" unless defined( my $child_pid = fork());
if ($child_pid) {  # If I have a child PID, then I must be the parentpush @children_pids, $child_pid;print "children's PIDs: @children_pids\n";
} else { # I am the childmy $wait_time = int(rand(10));sleep $wait_time;my $localtime = localtime;print "Child: Some child exited at $localtime\n";exit 0; # Exit the child
}

那么 Child process 的回收问题怎么解决?如果 Parent process 任由它自生自灭,就会导致Zombie process。

回收方法

有两种方式如下,无论哪种都涉及waitpid(),当然也可以使用wait()(不建议)
- Blocking wait
- Non blocking wait
在此提一下waitpid()下文code有使用

waitpid PID,FLAGS
PID: -1(stands for any child process) | pid ( > 0 )
FLAGS: 0 (for a blocking wait) | WHOHANG (return 0 or -1if no dead children)
i.e,. waitpid($pid, 0) ## in a blocking wait
waitpid(-1, WHOHANG) ## no blocking wait

Blocking wait

见如下code:

my @children_pids;
print "Parent: my pid $$\n";
for my $count (1..10){die "$@" unless defined( my $child_pid = fork());if ($child_pid) {  # If I have a child PID, then I must be the parentpush @children_pids, $child_pid;print "children's PIDs: @children_pids\n";} else { # I am the childmy $wait_time = int(rand(10));sleep $wait_time;my $localtime = localtime;print "Child: Some child exited at $localtime\n";exit 0; # Exit the child}
}foreach my $child (@children_pids) {print "Parent: Waiting on $child\n";waitpid($child, 0); ## will not go to next step unless $child reapedmy $localtime = localtime;print "Parent: Child $child was reaped - $localtime.\n";
}

Output:

[root@VTB93-PC1 ~]# perl /tmp/test_fork.pl
Parent: my pid 15117
children's PIDs: 15118
children's PIDs: 15118 15119
children's PIDs: 15118 15119 15120
children's PIDs: 15118 15119 15120 15121
children's PIDs: 15118 15119 15120 15121 15122
children's PIDs: 15118 15119 15120 15121 15122 15123
children's PIDs: 15118 15119 15120 15121 15122 15123 15124
children's PIDs: 15118 15119 15120 15121 15122 15123 15124 15125
children's PIDs: 15118 15119 15120 15121 15122 15123 15124 15125 15126
children's PIDs: 15118 15119 15120 15121 15122 15123 15124 15125 15126 15127
Parent: Waiting on 15118
Child: Some child exited at Thu Apr 21 13:28:48 2016
Parent: Child 15118 was reaped - Thu Apr 21 13:28:48 2016.
Parent: Waiting on 15119
Child: Some child exited at Thu Apr 21 13:28:48 2016
Child: Some child exited at Thu Apr 21 13:28:48 2016
Child: Some child exited at Thu Apr 21 13:28:50 2016
Child: Some child exited at Thu Apr 21 13:28:51 2016
Parent: Child 15119 was reaped - Thu Apr 21 13:28:51 2016.
Parent: Waiting on 15120
Child: Some child exited at Thu Apr 21 13:28:51 2016
Child: Some child exited at Thu Apr 21 13:28:52 2016
Child: Some child exited at Thu Apr 21 13:28:53 2016
Child: Some child exited at Thu Apr 21 13:28:54 2016
Parent: Child 15120 was reaped - Thu Apr 21 13:28:54 2016.
Parent: Waiting on 15121
Parent: Child 15121 was reaped - Thu Apr 21 13:28:54 2016.
Parent: Waiting on 15122
Parent: Child 15122 was reaped - Thu Apr 21 13:28:54 2016.
Parent: Waiting on 15123
Child: Some child exited at Thu Apr 21 13:28:54 2016
Parent: Child 15123 was reaped - Thu Apr 21 13:28:54 2016.
Parent: Waiting on 15124
Parent: Child 15124 was reaped - Thu Apr 21 13:28:54 2016.
Parent: Waiting on 15125
Parent: Child 15125 was reaped - Thu Apr 21 13:28:54 2016.
Parent: Waiting on 15126
Parent: Child 15126 was reaped - Thu Apr 21 13:28:54 2016.
Parent: Waiting on 15127
Parent: Child 15127 was reaped - Thu Apr 21 13:28:54 2016.

可以看出规律,回收的顺序是按照`fork()`的顺序, 可在实际中 child process 耗时有长有短,后fork()的process很有可能比较早的先结束,所以引入第二种Reap机制,使用$SIG{CHLD}

Non blocking wait

这里先提一下$SIG{CHLD}, 可接受的赋值如下:

SIG{CHLD} = ‘IGNORE’; ## Children reaped by systemSIG{CHLD} = ‘IGNORE’; ## Children reaped by system SIG{CHLD} = ‘DEFAULT’; ## System defined
$SIG{CHLD} = \&REAPER; ## do REAPER if SIGCHLD catched

use POSIX ":sys_wait_h";$SIG{CHLD}=\&REAPER;
sub REAPER {my $child;while(( $child = waitpid(-1, &WNOHANG)) > 0){my $localtime = localtime;print "Parent: Child $child was reaped - $localtime.\n";}$SIG{CHLD}=\&REAPER;
}
my @children_pids;
print "Parent: my pid $$\n";
for my $count (1..10){die "$@" unless defined( my $child_pid = fork());if ($child_pid) {  # If I have a child PID, then I must be the parentpush @children_pids, $child_pid;print "children's PIDs: @children_pids\n";} else { # I am the childmy $wait_time = int(rand(10));sleep $wait_time;my $localtime = localtime;print "Child: Some child exited at $localtime\n";exit 0; # Exit the child}
}
## Keep parent alive to reap all children
while (1) {sleep;
}

Outpuit:

Parent: my pid 15189
children's PIDs: 15194
children's PIDs: 15194 15195
children's PIDs: 15194 15195 15196
children's PIDs: 15194 15195 15196 15197
children's PIDs: 15194 15195 15196 15197 15198
children's PIDs: 15194 15195 15196 15197 15198 15199
children's PIDs: 15194 15195 15196 15197 15198 15199 15200
children's PIDs: 15194 15195 15196 15197 15198 15199 15200 15201
children's PIDs: 15194 15195 15196 15197 15198 15199 15200 15201 15202
children's PIDs: 15194 15195 15196 15197 15198 15199 15200 15201 15202 15203
Child: Some child exited at Thu Apr 21 13:42:25 2016
Parent: Child 15202 was reaped - Thu Apr 21 13:42:25 2016.
Child: Some child exited at Thu Apr 21 13:42:27 2016
Parent: Child 15197 was reaped - Thu Apr 21 13:42:27 2016.
Child: Some child exited at Thu Apr 21 13:42:29 2016
Parent: Child 15201 was reaped - Thu Apr 21 13:42:29 2016.
Child: Some child exited at Thu Apr 21 13:42:30 2016
Parent: Child 15194 was reaped - Thu Apr 21 13:42:30 2016.
Child: Some child exited at Thu Apr 21 13:42:31 2016
Parent: Child 15198 was reaped - Thu Apr 21 13:42:31 2016.
Child: Some child exited at Thu Apr 21 13:42:31 2016
Parent: Child 15200 was reaped - Thu Apr 21 13:42:31 2016.
Child: Some child exited at Thu Apr 21 13:42:31 2016
Parent: Child 15203 was reaped - Thu Apr 21 13:42:31 2016.
Child: Some child exited at Thu Apr 21 13:42:32 2016
Parent: Child 15199 was reaped - Thu Apr 21 13:42:32 2016.
Child: Some child exited at Thu Apr 21 13:42:33 2016
Parent: Child 15195 was reaped - Thu Apr 21 13:42:33 2016.
Child: Some child exited at Thu Apr 21 13:42:34 2016
Parent: Child 15196 was reaped - Thu Apr 21 13:42:34 2016.

可以看出但某个Child exit 后会发送SIGCHLD给Parent,顺序依据exit先后。当然,这是Parent跟踪Children(如获取返回信息local $?,以上都返回 0 )并作出相应操作。如果无需如此,可直接$SIG{CHLD}='INGNORE'; 交给OS吧。

总结

  • 使用 SIGCHLD REAPER 更符合现实场景,结合waitpid()Non blocking wait 方式
  • Parent 负责 Children 的生命周期,以免出现 Zombie process
  • PID 1 init ## 所有Process 的 parent

[Perl]REAPER相关推荐

  1. perl: warning: Setting locale failed. Falling back to a fallback locale (“en_HK.UTF-8“).

    1. 问题描述 perl: warning: Setting locale failed. perl: warning: Please check that your locale settings: ...

  2. perl语言编程 第四版_2020年,5 种 将死的编程语言!

    来源 | 码农网译者 | 小峰 曾几何时,几乎每个人都在使用Perl语言编程.但是那些经常使用的人慢慢地发现,关于这个Perl语言似乎总是有点不对劲.至少我知道有这么个叫做"piecemea ...

  3. java perl_在Java中调用Perl脚本

    有两种方法,种是直接 Runtime.getRuntime().exec("..."); 这里推荐第二种,可以得到输出和返回值:源代码如下: import java.io.Buff ...

  4. perl 如何更新_Perl 进度条模块

    Term::ProgressBar 模块是一个可以用于生成进度条的 Perl 模块. 安装:cpan -i Term::ProgressBar 最小脚本,展示如何最快学会使用该模块: #!/usr/b ...

  5. PEAR, PECL和Perl的区别

    PEAR是PHP扩展与应用库(the PHP Extension and Application Repository)的缩写.它是一个PHP扩展及应用的一个代码仓库,简单地说,PEAR就是PHP的C ...

  6. Brian 的 Perl 问题之万能指南

    为什么80%的码农都做不了架构师?>>>    PerlChina brian's Guide to Solving Any Perl Problem Home Page | All ...

  7. perl 的基本数据类型

    1.变量 scalar:$varname 变量 数组:  @varnanme Hsah:  %varname 文件:  通常大写字母 2.变量名的命名规则 简单变量以$开头后面跟字母数字或者下划线: ...

  8. Perl的Hash一个小细节

    2019独角兽企业重金招聘Python工程师标准>>> 很多天前,使用了别人的Perl代码. 看到一个语法+{},想了好久不知道啥意思. 后来翻阅了一些资料,发现Perl用这个语法来 ...

  9. perl 编程 - 判断系统进程是否活着的方法

    2019独角兽企业重金招聘Python工程师标准>>> 前言:我在使用perl编写CGI程序时遇到的一些问题,解决以后,记录一下我的心得,有心的朋友们会从中得到帮助并养成正确使用的好 ...

最新文章

  1. Linux 学习基础入门之Linux发展史
  2. [CF125E]MST Company
  3. ffmpeg图片压缩为视频
  4. 编写递归调用的Lambda表达式
  5. 用户解锁不存在_解锁手机有6种方法,这些常识你知道吗?小白购机指南——解锁篇...
  6. c# 弹性和瞬态故障处理库Polly 学习
  7. mysql连接字符串加密配置文件_Asp.net2.0如何加密Web.config配置文件数据库连接字符串...
  8. 一只老猴子说的话,太经典了!
  9. let的解构赋值_解构赋值还有这么多玩法?
  10. 总结SlickEdit的快捷键,分享当前自用配置
  11. 键盘上的prtsc,scrlk,pause键作用
  12. Air202学习 一 (程序下载流程----GPIO简单控制)
  13. 中国内地LCD液晶屏原材料仍正在发展中(二)
  14. 探索变量之间的关系(python3)
  15. 干货|语义网、Web3.0、Web3、元宇宙这些概念还傻傻分不清楚?(下)
  16. 由Tomcat 8005端口想到的...
  17. python matplotlib绘制折线图_Matplotlib实践系列:折线图完全示例
  18. Win7+Ubuntu双系统安装教程
  19. CHAR与TCHAR处理函数
  20. 恒大研究院|中国最具发展潜力的100个城市

热门文章

  1. 利用U盘重装系统的方法
  2. 如何区别与选择嵌入式产品中的ARM核心板?
  3. 初学js和css简单总结
  4. multiset用法 oracle,oracle cast multiset table 语法演示
  5. IPO被否,灿星文化还能保住“综艺王座”吗?
  6. \r,\n与\r\n有什么区别?
  7. 配置dm-mpp集群
  8. 2022php面试题
  9. python基础编程:Python简单基础小程序的实例代码
  10. java线程池的工作原理_JAVA线程池原理详解一