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等的區別
第一我的解釋:
第二我的解釋: