在 linux 中 fork 是乙個非常重要的函式,它從乙個已經存在的程序中建立出了乙個新程序,這個新程序稱為子程序,而原程序稱為父程序。
對於很多初學者來說,這是最不能理解的。的確,這只能說是看起來像,因為從彙編的層面就已經決定了棧的壓棧和出棧是成對出現的,乙個函式永遠只會返回一次。fork 函式的返回兩次只是乙個表面現象,那本質上是怎麼回事呢?
fork 函式呼叫之後,就會為子程序建立乙個新的 pcb,子程序就會完全拷貝父程序的位址空間,包括堆、棧、**段都被拷貝了過來,因此,子程序的棧是從父程序那拷貝過來的,那麼它和父程序的函式棧幀就是完全相同的,在函式執行完畢後,父子程序在各自的函式棧幀中返回,造成了我們所看到的兩次返回的假象。
通常情況下,我們總是用 sleep 等操作來保證另乙個程序先執行,但父子程序誰先執行並不是不可**的。從linux核心2.6.32開始,在預設情況下,父程序將成為fork之後優先排程的物件。採取這種策略的原因很簡單:fork是父程序發起的呼叫,因此fork之後,父程序在cpu中處於活躍的狀態,並且其記憶體管理資訊也被置於硬體記憶體單元的轉譯後備緩衝器(tlb),所以先排程父程序無論從減少上下文切換、cpu讓出等方面都可以提高效能。linux核心從2.6.24開始,核心採用完全公平排程(cfs),使用者建立的普通程序,都採用cfs排程策略。對於cfs排程策略,核心提供的控制選項預設是0,表示父程序優先獲得排程,如果該值被改為1,子程序會優先獲得排程。
但posix標準和linux都沒***會優先排程父程序,因此在應用中,我們不能對父子程序的執行順序做任何假設。如果確實需要父子程序的某一特定執行順序,那麼還是得需要程序間的同步手段。
fork 函式最常規的用法:乙個父程序希望複製自己,使父子程序同時執行不同的**,這時就需要在子程序中呼叫 exec 族函式來使子程序丟棄當前拷貝父程序的所有**段,並建立新的**段和堆疊。在這種情況下如果還讓子程序在一開始就完全拷貝父程序的位址空間,顯然是一種很不明智的做法,因此linux引入了寫時拷貝(copy-on-write)的方法。
寫時拷貝,從字面上來理解就是寫的時候才拷貝,具體來說就是指子程序 pcb 的頁表指向與父程序相同的物理記憶體頁,這樣就只拷貝父程序的頁表項即可,但這個時候記憶體中的所有內容都是唯讀的,如果父子程序都對記憶體進行唯讀操作,那麼這個狀態就可以一直保持下去,一旦有一方想要對記憶體進行寫操作,就會引發缺頁異常,此時,核心才會為子程序申請乙個新的物理頁,並將原物理頁中的內容真正的複製到新的物理頁中,讓父子進**正擁有各自的物理記憶體頁,此時他們各自記憶體中的內容就是可寫的了。
fork函式到底做了什麼?
實體地址和邏輯位址 或稱虛擬位址 的概念。使用者程式看不見真正的實體地址。使用者只生成邏輯位址,且認為程序的位址空間為0到max。實體地址範圍從r 0到r max,r為基位址,位址對映 將程式位址空間中使用的邏輯位址變換成記憶體中的實體地址的過程。由記憶體管理單元 mmu 來完成。fork 會產生乙...
你到底做了什麼
從1月份 一直到現在,有沒有人問過自己,你到底做過了什麼,又做成了什麼。已經有4個月沒有碰過所謂的課本,一直也提不起學習的興趣,不過我做事一般不會後悔,我沒有學習,雖然這並不對,但是起碼我並沒有浪費自己的時間,我去玩也好,我睡覺也好,我度過了別人所沒有的生活,我也交往了新的朋友,新的老師,雖然與許多...
再論DUPLICATE到底做了什麼!
什麼是使用duplicate的原因?一直想知道oracle在duplicate中到度隱藏了什麼,既然在做duplicate時oracle要將所有備份檔案複製到目標機上那又為什麼要同時連線兩個庫 target instance and auxiliary instance.開始以為是使用了源機器上的控...