perl做为一种解释性的语言,很是受广大系统管理员的欢迎,优势么就很少说了,坏处也有很多,好比对线程的支持,就一直不咋地,因此大多数状况下,咱们都需要多个进程,来帮助咱们完毕工做,闲话少说,上代码。linux
运行结果例如如下:
Child: My pid = 19481
Parent My pid = 19480, and my child's pid = 19481
(5秒钟等待)
Child: end
Parent: end
父进程派生子进程,之需要一条命令,那就是fork,fork函数的返回值赋给一个变量,上例中赋给了"$pid",接下来,就要依据$pid值的不一样,来分三种状况了。
一、fork失败的状况:这个时候,$pid处于没有定义的状态,上例中作的一个"if (!defined($pid))"的推断,假设为真,说明$pid没有定义,fork失败,这个时候就要打印错误信息,并且退出。
二、子进程:假设是子进程,那么$pid的值为0,就是上例中"if ($pid == 0)"条件为真的情况,在"$pid == 0"的时候,那就都是子进程了,上例中,子进程将本身的pid打出来,为19481。
三、父进程:假设是父进程,那么$pid的值为它派生出的子进程的pid,也就是不为0,就是else的状况,上例中把$pid打出来,可以看到,也是 19481,就是子进程的pid值。
这仅仅是一个最简单的样例,一个父进程派生一个子进程,再略微复杂一点,一个父进程派生多个子进程,代码例如如下:函数
这个样例就是,父进程运行一个循环,每次循环都fork一个子进程,子进程运行完之后退出,每次循环都等待1s,循环10次。
运行结果例如如下:
Child 0 : My pid = 20499
Child 1 : My pid = 20500
Child 2 : My pid = 20501
Child 3 : My pid = 20502
Child 4 : My pid = 20503
Child 0 : end
Child 5 : My pid = 20506
Child 1 : end
Child 6 : My pid = 20507
Child 2 : end
Child 7 : My pid = 20508
Child 3 : end
Child 8 : My pid = 20509
Child 4 : end
Child 9 : My pid = 20510
Child 5 : end
[root@localhost /tmp]
# Child 6 : end
Child 7 : end
Child 8 : end
Child 9 : end
每个子进程耗时5s,那么运行完总共需要的是15s。
但是,这种代码会致使一个问题,在运行的过程当中,可以在另外的tty上输入ps auxf来查看当前的进程状态,会发现相似这种东东:
root 20531 0.0 0.0 8460 1704 pts/2 S+ 21:46 0:00 \_ perl test_proc_1.pl
root 20532 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 \_ [perl]
root 20535 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 \_ [perl]
root 20536 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 \_ [perl]
root 20539 0.0 0.0 0 0 pts/2 Z+ 21:46 0:00 \_ [perl]
root 20541 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 \_ perl test_proc_1.pl
root 20543 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 \_ perl test_proc_1.pl
root 20545 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 \_ perl test_proc_1.pl
root 20546 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 \_ perl test_proc_1.pl
root 20548 0.0 0.0 8460 720 pts/2 S+ 21:46 0:00 \_ perl test_proc_1.pl
有4个进程,状态为Z,意思就是僵尸进程,而正常的程序,是不该该出现僵尸进程的。
正常状况下,子进程的退出需要作两件事情,第一,子进程exit,发出一个信号给本身的父进程,第二,父进程对子进程进行回收,假设父进程已经不存在了,那子进程会将init,也就是linux中第一个进程做为本身的父进程,init会取代它的父进程对子进程进行回收。
咱们的状况就是,子进程已经调用了exit,但是父进程并无对它进行回收,假设父进程持续fork子进程,那僵尸进程就会愈来愈多,愈来愈多,最后会致使什么后果,我就不说了。
父进程回收子进程的函数有两个:
wait,和waitpid
wait函数比較简单,没有不论什么參数,调用之后,父进程会停住,而后等待子进程返回。假设没有子进程,返回-1
waitpid有两个參数,第一个參数为要等待的子进程的pid值,另一个是flag,通常来说,第一个參数为-1,意思就是等待所有的子进程。调用方法例如如下:this
事实上,最基本的是让父进程知道,何时才需要去回收已经退出的子进程,因为父进程也是有很是多活需要忙的。
这个可以经过信号来实现,子进程在退出的时候,会向父进程发送一个信号,咱们仅仅要捕获了这个信号,就知道,有些子进程需要回收啦。样例例如如下:spa
运行结果和原先同样:
Child 0 : My pid = 21552
Child 1 : My pid = 21553
Child 2 : My pid = 21554
Child 3 : My pid = 21555
Child 4 : My pid = 21556
Child 0 : end
Child 5 : My pid = 21558
Child 1 : end
Child 6 : My pid = 21570
Child 2 : end
Child 7 : My pid = 21572
Child 3 : end
Child 8 : My pid = 21574
Child 4 : end
Child 9 : My pid = 21575
Child 5 : end
[root@localhost /tmp]
# Child 6 : end
Child 7 : end
Child 8 : end
Child 9 : end
但是ps auxf的结果就有很是大区别了:
root 21551 0.1 0.0 8280 2672 pts/2 S+ 22:06 0:00 \_ perl test_proc_2.pl
root 21558 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 \_ perl test_proc_2.pl
root 21570 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 \_ perl test_proc_2.pl
root 21572 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 \_ perl test_proc_2.pl
root 21574 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 \_ perl test_proc_2.pl
root 21575 0.0 0.0 8280 1168 pts/2 S+ 22:07 0:00 \_ perl test_proc_2.pl
僵尸进程不会存在了。
$SIG{CHLD} = sub { $zombies++ }; 这条语句,事实上就是捕获了子进程退出的时候,向父进程发出的信号,捕获之后,就给一个变量($zombies)加1。
假设"$zombies"不为0的时候,那就说明,有子进程退出了,需要进行回收,那父进程就调用waidpid函数,进行一次回收,每回收一个子进程,就给这个变量减去1,这样当"$zombies"减为0的时候,就说明所有的僵尸进程都已经回收了。bingo!
有的时候,咱们仅仅是运行必定量的任务,仅仅管fork就可以了,但是某些时候,咱们有太多任务需要运行,要一直持续的fork好多子进程,但是咱们但愿把子进程的数目控制在一个范围内,比方说,我一个任务,需要有100个子进程来运行,但是我不能100个进程全部fork出去,这样太占用资源了,因此我但愿把进程数量控制在10个之内,当第一个进程退出之后,我再fork第11个进程,样例例如如下:线程
运行结果例如如下:
Child 0 : My pid = 22641
Child 1 : My pid = 22642
Child 2 : My pid = 22643
Child 0 : end
Child 3 : My pid = 22645
Child 1 : end
Child 4 : My pid = 22647
Child 2 : end
Child 5 : My pid = 22658
Child 3 : end
Child 6 : My pid = 22660
Child 4 : end
Child 7 : My pid = 22661
Child 5 : end
Child 8 : My pid = 22663
Child 6 : end
Child 9 : My pid = 22664
Child 7 : end
[root@localhost /tmp]
# Child 8 : end
Child 9 : end
同一时候,看到的ps auxf的输出例如如下:
root 22640 0.0 0.0 8116 2672 pts/2 S+ 22:28 0:00 \_ perl test_proc_3.pl
root 22660 0.0 0.0 0 0 pts/2 Z+ 22:29 0:00 \_ [perl]
root 22661 0.0 0.0 8116 1168 pts/2 S+ 22:29 0:00 \_ perl test_proc_3.pl
root 22663 0.0 0.0 8116 1168 pts/2 S+ 22:29 0:00 \_ perl test_proc_3.pl
root 22664 0.0 0.0 8116 1168 pts/2 S+ 22:29 0:00 \_ perl test_proc_3.pl
第一个子进程需要5s才干退出,假设1s运行一次fork的话,那么同一时候应该有5个子进程,但是本例中仅仅有三个,那就是说实现了对进程数量的控制。
本例中定义了几个变量:
$num_proc:正在活动的进程数量,控制在3个之内,因此在父进程每次fork完子进程后,都会检查这个变量,假设超出了3个,那就等一会。当父进程fork了新子进程的时候,这个数字会添加,当子进程退出之后,父进程捕获了信号,这个数字会下降。
$num_collect:已回收的进程数量,每回收一个子进程,变量加一。
$i:已经fork的进程数量。
$num_proc和$num_collect的和应该是等于$i的,假设不等于了,那就说明,有子进程需要回收了。进程