https://www.cnblogs.com/f-ck-need-u/p/9693675.htmlhtml
fork是低层次的系统调用,经过复制父进程来建立子进程。shell
#!/usr/bin/perl use 5.010; my $pid=fork(); say $pid, "========";
fork用来拷贝当前进程,生成一个基本彻底同样的子进程。less
my $pid=fork();
若是fork成功:spa
若是fork失败,将对父进程返回undef,并设置错误信息。fork失败的可能缘由有:code
执行该程序,将返回两行数据:orm
1
262620====== 0======
其中第一行输出是父进程输出的,第二行是子进程输出的。htm
虽然这里父进程先输出,但fork成功以后,父、子进程并无执行的前后顺序,也可能cpu会先调度到上子进程去执行。blog
root@vm3110 [11:06:32 AM] [~/test_perl] -> # ./testfork.pl 30598======== 0======== root@vm3110 [11:06:33 AM] [~/test_perl] -> # ./testfork.pl 30608======== root@vm3110 [11:06:34 AM] [~/test_perl] -> # 0======== ./testfork.pl 0======== 30618========
注意上图中子进程部分只画了"say"那行语句,但实际上子进程是彻底复制父进程的,子进程也能够有say前面的那段语句(好比那个fork语句),进程
但因为父进程的状态已经执行完了fork,因此子进程也是从fork语句以后开始执行的,fork语句以前的语句对于子进程来讲是透明的。ip
并且按照写时复制的技术,子进程用不到它因此不会复制fork前面的代码(注:也就是说子进程和父进程是共享代码的)。
更复杂的例子
#!/usr/bin/perl use 5.010; print "id1: ", $pid, "\n"; my $pid=fork; print "id2: ",$pid,"\n"; if (!$pid) { say "child process: ",$pid; } waitpid($pid, 0); say "parent process: ", $pid;
id1: id2: 30678 id2: 0 child process: 0 parent process: 0 parent process: 30678
首先perl进程输出id1。而后fork一个子进程,这时有两条执行路线。假如fork后先执行父进程,则:
$pid
,因为fork返回给子进程的pid变量值为0,因此if判断经过,因而子进程输出"child process"$pid=0
,waitpid()的等待pid为0时,表示等待以本身为leader进程的进程组中的其它进程,因为没有进程组,因此waitpid失败假如fork以后,先执行子进程,且还先把子进程执行完了,cpu才调度到父进程,则也没有影响,子进程执行完毕后,早晚会调度到父进程,而父进程的waitpid($pid)
已经没有子进程了,因而waitpid()失败(返回-1),继续向下执行。
显然,上面fork的代码有一些问题。因为fork建立子进程以后。父、子进程都继续执行,且执行的前后顺序不定。因此:
大概代码以下:
my $pid=fork; unless($pid){ # 判断子进程的语句紧跟着fork CODE1; exit; # 要让子进程退出 } waitpid($pid,0); # 要等待子进程 CODE2;
fork和exec结合
通常fork和exec会一块儿用,fork用来建立新的子进程,exec启动一个程序替代当前子进程并在子进程结束时退出子进程。
例如system "date"
命令,替换为低层次的fork+exec+waitpid。
#!/usr/bin/perl use 5.010; defined(my $pid=fork) or die "Cannot fork: $!"; unless($pid) { #进入到这里执行的,表示进入子进程 exec 'date'; # exec正确执行时,执行完后将结束子进程 die "cannot exec date: $!"; #exec 启动失败时,将执行die来结束子进程 } #这里表示是父进程,由于exec执行的子进程自动结束了子进程。 waitpid($pid, 0);
Tue Dec 10 11:26:13 CST 2019 pid => 30813.
system、exec、fork等的区别
第一我的解释:
第二我的解释: