1. 程式人生 > 其它 >2020.12.8Linux學習筆記————程序 fork() 和 pid

2020.12.8Linux學習筆記————程序 fork() 和 pid

技術標籤:Linux作業系統

Linux學習筆記————程序 fork() 和 pid

fork呼叫的一個奇妙之處就是它僅僅被呼叫一次,卻能夠返回兩次,它可能有三種不同的返回值:
1)在父程序中,fork返回新建立子程序的程序ID;
2)在子程序中,fork返回0;
3)如果出現錯誤,fork返回一個負值;

建立新程序成功後,系統中出現兩個基本完全相同的程序,這兩個程序執行沒有固定的先後順序,哪個程序先執行要看系統的程序排程策略。此時,兩個程序都從fork開始往下執行,只是pid不同。
有人可能疑惑為什麼不是從#include處開始複製程式碼的?

看下圖:

  上圖表示一個含有fork的程式,而fork語句可以看成將程式切為A、B兩個部分。然後整個程式會如下執行:

  step1、設由shell直接執行程式,生成了程序P。P執行完Part. A的所有程式碼。

  step2、當執行到pid = fork();時,P啟動一個程序Q,Q是P的子程序,和P是同一個程式的程序。Q繼承P的所有變數、環境變數、程式計數器的當前值。

  step3、在P程序中,fork()將Q的PID返回給變數pid,並繼續執行Part. B的程式碼。

  step4、在程序Q中,將0賦給pid,並繼續執行Part. B的程式碼。

  這裡有三個點非常關鍵:

  1、P執行了所有程式,而Q只執行了Part. B,即fork()後面的程式。(這是因為Q繼承了P的PC-程式計數器)

  2、Q繼承了fork()語句執行時當前的環境,而不是程式的初始環境。

  3、P中fork()語句啟動子程序Q,並將Q的PID返回,而Q中的fork()語句不啟動新程序,僅將0返回。
#include <unistd.h> 
#include <sys/types.h>

main () 
{ 
         pid_t pid; 
         printf("hello!\n");  
         pid=fork();

         if (pid < 0) 
                 printf("error in fork!"); 
         else if (pid == 0) 
                 printf("i am the child process, my process id is %d\n "
,getpid()); else printf("i am the parent process, my process id is %d\n",getpid()); printf("bye!\n"); }

在這裡插入圖片描述

這裡可以看出parent process執行了printf(“hello!\n”); 而child process 沒有執行printf(“hello!\n”);

有一個讓人很迷惑的例子:

#include <unistd.h>
#include <sys/types.h>
main () { pid_t pid; printf("fork!"); //printf("fork!\n") pid=fork(); if (pid < 0) printf("error in fork!\n"); else if (pid == 0) printf("i am the child process, my process id is %d\n",getpid()); else printf("i am the parent process, my process id is %d\n",getpid()); }

在這裡插入圖片描述

此時列印輸出了兩個fork!這不免讓人以為是child process從#include處開始執行,所以也執行了printf(“fork!”); 語句。

其實不然,出現這種問題的原因在於:

這就跟Printf的緩衝機制有關了,printf某些內容時,作業系統僅僅是把該內容放到了stdout的緩衝佇列裡了,並沒有實際的寫到螢幕上 。但是,只要看到有\n, 則會立即重新整理stdout,因此就馬上能夠列印了.

mian函式(parent process)運行了printf(“fork!”) 後, "fork!“僅僅被放到了緩衝裡,再執行到fork時,緩衝裡面的 AAAAAA 被子程序(child process)繼承了,因此在子程序度stdout緩衝裡面就也有了"fork!”。所以,你最終看到的會是 “fork!” 被printf了2次!!!
而mian函式(parent process)執行 printf(“fork!\n”)後,“fork!” 被立即列印到了螢幕上,之後fork到的子程序(child process)裡的stdout緩衝裡不會有"fork!“內容 因此你看到的結果會是"fork!” 被printf了1次!!!