linux/unix進程的建立

來源:互聯網
上載者:User

linux/unix進程的建立 在 UNIX 系統中,使用者建立一個新進程的唯一方法就是調用系統調用 fork。調用 fork 的進程稱
為父進程,而新建立的進程叫做子進程。系統調用的文法格式: pid = fork(); 在從系統調用 fork 中返回時,兩個進程除了傳回值 pid 不同外,具有 完全一樣的使用者級上下文。
在子進程中,pid 的值為零。在系統啟動時由核心內 部地建立的進程0是唯一不通過系統調用
fork 而建立的進程。核心為系統調用 fork 完成下列操作:  www.2cto.com  1.  為新進程在進程表中分配一個空項。2.  為子進程賦一個唯一的進程標識號 (PID)。 3.  做一個父進程內容相關的邏輯副本。由於進程的某些部分,如本文區,可能被幾個進程所共
享,所以核心有時只要增加某個區的引用數即可,而不是真的將該區拷貝到一個 新的內
存物理區。 4.  增加與該進程相關聯的檔案表和索引節點表的引用數。5.  對父進程返回子進程的進程號,對子進程返回零。理解系統調用 fork 的實現是十分重要的,因為子進程就象從天而降一樣地開始 它的執行序列。下面是系統調用 fork 的演算法。核心首先確信有足夠的資源來成功完成 fork。 如果資源不滿足
要求,則系統調用 fork 失敗。如果資源滿足要求,核心在進程 表中找一個空項,並開始構
造子進程的上下文。   www.2cto.com  演算法:fork輸入:無輸出:對父進程是子進程的 PID          對子進程是0{         檢查可用的核心資源         取一個閒置進程表項和唯一的 P識別碼         檢查使用者沒有過多的運行進程         將子進程的狀態設定為“建立”狀態         將父進程的進程表中的資料拷貝到子進程表中         目前的目錄的索引節點和改變的根目錄(如果可以)的引用數加1         檔案表中的開啟檔案的引用數加1         在記憶體中作父進程內容相關的拷貝         在子進程的系統級上下文中壓入虛設系統級上下文層                 /* 虛設上下文層中含有使子進程能                  * 識別自己的資料,並使子進程被調度時                  * 從這裡開始運行                  */         if (正在執行的進程是父進程) {                 將子進程的狀態設定為“就緒”狀態                 return (子進程的 PID)                       // 從系統到使用者         }         else {                 初始化計時區                 return 0;         }}我們來看看下面的例子。該程式說明的是經過系統調用 fork 之後,對檔案的 共用存取。使用者
調用該程式時應有兩個參數,一個是已經有的檔案名稱,另外一個是要 建立的新檔案名稱。該進
程開啟已有的檔案,建立一個新檔案,然後,假定沒有遇見過錯誤,它調用 fork 來建立一個
子進程。子進程可以通過使用相同的檔案描述符而繼承地存取父進程的檔案(即父進程已經打
開和建立的檔案)。  www.2cto.com  當然,父進程和子進程要分別獨立地調用 rdwrt 函數,並執行一個迴圈,即從 源檔案中讀一
個位元組,然後寫一個位元組到目標檔案中區。當系統調用 read 遇見 檔案尾時,函
數 rdwrt 立即返回。 #include <fcntl.h> int      fdrd, fdwt;char     c; main(int argc, char *argv[]){         if (argc != 3) {                 exit(1);         }         if ((fdrd = open(argv[1], O_RDONLY)) == -1) {                 exit(1);         }         if ((fdwt = creat(argv[2], 0666)) == -1) {                 exit(1);         }          fork();         // 兩個進程執行同樣的代碼         rdwrt();         exit(0);} rdwrt(){         for (;;) {                 if (read(fdrd, &c, 1) != 1) {                          return ;                 }                 write(fdwt, &c, 1);         }}在這個例子中,兩個進程的檔案描述符都指向相同的檔案表項。這兩個進程永遠 不會讀
或寫到相同的檔案位移量,因為核心在每次 read 和 write 調用 之後,都要增加檔案的位移量。儘管兩個進程似
乎是將源檔案拷貝了兩次,但因為他們分擔了工作任務,因此,目標檔案的內容依賴於核心調度兩個進程的次序。 如果 核心這樣調度兩個進程:使他們交替地執行他們的系統調用,或甚至使他們交替地
執行每對 read 和 write 調用,則目標檔案的內容和源檔案的內容完全一致。 但考慮這樣的情況:兩個進程正要讀源檔案中的兩個連續的字元 "ab"。假定父進程讀了
字 符 "a",這時,核心在父進程寫之前,做了環境切換來執行子進程。 如果子進程 讀到字元 "b",並在父進程被調度前,將它寫到目標檔案,那麼目標檔案將
不再含有 字串 "ab",而是含有 "ba"了。核心並不保證進程執行的相對速率。再來看看另外一個例子: #include <string.h> char     string[] = "Hello, world"; main(){         int      count, i;         int      to_par[2], to_chil[2];             // 到父、子進程的管道         char     buf[256];          pipe(to_par);         pipe(to_chil);          if (fork() == 0) {                 // 子進程在此執行                 close(0);                 // 關閉老的標準輸入                 dup(to_child[0]); // 將管道的讀複製到標準輸入                 close(1);                 // 關閉老的標準輸出                 dup(to_par[1]);           // 將管道的寫複製到標準輸出                 close(to_par[1]); // 關閉不必要的管道描述符                 close(to_chil[0]);                 close(to_par[0]);                 close(to_chil[1]);                 for (;;) {                          if ((count = read(0, buf, sizeof(buf)) == 0)                                   exit();                          write(1, buf, count);                 }          }          // 父進程在此執行         close(1);                 // 重新設定標準輸入、輸出         dup(to_chil[1]);         close(0);         dup(to_par[0]);         close(to_chil[1]);         close(to_par[0]);         close(to_chil[0]);         close(to_par[1]);         for (i = 0; i < 15; i++) {                 write(1, string, strlen(string));                 read(0, buf, sizeof(buf));         }}子進程從父進程繼承了檔案描述符0和1(標準輸入和標準輸出)。兩次執行系統調用 pipe 分別在數組 to_par 和 to_chil 中分配了兩個檔案描述符。然後該
進程 執行系統調用 fork,並複製進程上下文:象前一個例子一樣,每個進程存取 自己的
私人資料。 父進程關閉他的標準輸出檔案(檔案描述符1),並複製(dup)從管道線 to_chil 返回的寫文
件描述符。因為在父進程檔案描述符表中的第一個空槽是剛剛 由關閉騰出來的,所以核
心將管道線寫檔案描述符複製到了檔案描述符表中的第一項中,這樣,標準輸出檔案描
述符變成了管道線 to_chil 的寫檔案描述符。  www.2cto.com  父進程以類似的操作將標準輸入檔案描述符替換為管道線 to_par 的讀檔案 描述符。與此
類似,子進程關閉他的標準輸入檔案(檔案描述符0),然後複製 (dup) 管道 線 to_chil 的
讀檔案描述符。 由於檔案描述符表的第一個空項是原先的標準輸入項,所以子進程的標準輸入變成了管道
線 to_chil 的讀檔案描述符。子進程做一組類似的操作使他的標準輸出變成管道線 to_par
的寫檔案描述符。 然後兩個進程關閉從 pipe 返回的檔案描述符。上述操作的結果是:當父進程向標準輸出
寫東西的時候,他實際上是寫向 to_chil--向子進程發送資料,而子進程則從他的標準輸入
讀管道線。當子進程向他的標準輸出寫的時候, 他實際上是寫入 to_par--向父進程發送
資料,而父進程則從他的標準輸入 接收來自管道線的資料。兩個進程通過兩條管道線
交換訊息。無論兩個進程執行的順序如何,這個程式執行的結果是不變的。他們可能去執行睡眠和
喚醒來等待對方。父進程在15次迴圈後退出。然後子進程因管道線沒有寫進程而讀
到“檔案尾”標誌,並退出。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.