fork函式
在諸多應用中,創建多個行程是任務分解時行之有效的方法,例如,某一網路服務器行程可在偵聽客戶端請求的同時,為處理每---請求而創建一新的子行程,與此同時,服務器行程會繼續偵聽更多的客戶端連接請求,以此類手法分解任務,通常會簡化應用程式的設計,同時提高了系統的并發性,(即,可同時處理更多的任務或請求,)
1 #include <sys/types.h> 2 #include <unistd.h> 3 pid_t fork(void); //回傳:子行程中為0,父行程中為子行程I D,出錯為-1
執行呼叫后將存在兩個行程,且每個行程都會從fork()的回傳處繼續執行,
這兩個行程將執行相同的程式文本段,但卻各自擁有不同的堆疊段、資料段以及堆段拷貝,子行程的堆疊、資料以及堆疊段開始時是對父行程記憶體相應各部分的完全復制,執行fork()之后,每個行程均可修改各自的堆疊資料、以及堆段中的變數,而并不影響另一行程,
注:現在很多的實作并不做一個父行程資料段和堆的完全拷貝,因為在fork之后經常跟隨著exec,作為替代,使用了在寫時復制( Copy-On-Write, COW)的技術,這些區域由父、子行程共享,而且內核將它們的存取許可權改變為只讀的,(詳見Linux|Unix系統編程手冊)
程式代碼則可通過fork()的回傳值來區分父、子行程,在父行程中,fork()將 回傳新創建子行程的行程ID,
當無法創建子行程時,fork()將回傳-1, 失敗的原因可能在于,行程數量要么超出了系統針對此真實用戶(realuser ID)在行程數量.上所施加的限制(RLIMIT_ NPROC),要么是觸及允許該系統創建的最大行程數這一系統級上限,
一般來說,在fork之后是父行程先執行還是子行程先執行是不確定的,這取決于內核所使用的調度演算法,如果要求父、子行程之間相互同步,則要求某種形式的行程間通信,
例子:
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<unistd.h> 4 #include<sys/wait.h> 5 #include<stdlib.h> 6 #include<errno.h> 7 #include<string.h> 8 9 int main() 10 { 11 pid_t childPid; 12 /* if((childPid=fork())==-1) 13 { 14 printf("Fork error %s\n",strerror(errno)); 15 exit(1); 16 } 17 else 18 if(childPid==0) 19 { 20 printf("I am the child : %d\n",getpid()); 21 exit(0); 22 } 23 else 24 { 25 printf("I am the father : %d\n",getpid()); 26 exit(0); 27 } */ 28 switch(childPid=fork()){ 29 case -1: 30 printf("Fork error %s\n",strerror(errno)); 31 exit(1); 32 case 0: 33 printf("I am the child : %d\n",getpid()); 34 exit(0); 35 default: 36 printf("I am the father : %d\n",getpid()); 37 exit(0); 38 39 } 40 return 0; 41 }View Code
結果:

vfork函式
類似于fork(), vfork()可以為呼叫行程創建一個新的子行程,然而,vfork()是為子行程立即執行exec()的程式而專門設計的,
#include <sys/types.h> #include <unistd.h> pid_t vfork(void); //回傳:子行程中為0,父行程中為子行程I D,出錯為-1
vfork()與fork()一樣都創建一個子行程, 但是它并不將父行程的地址空間完全復制到子行程中,因為子行程會立即呼叫 exec (或exit),于是也就不會存訪該地址空間,不過在子行程呼叫 exec或exit之前,它在父行程的空間中運行,vfork()和fork()之間的另一個區別是:vfork()保證子行程先運行,在它呼叫exec或exit之后父行程才可能被調度運行,(如果在呼叫這兩個函式之前子行程依賴于父行程的進一步動作,則會導致死鎖,)
注:由于子行程使用父行程的記憶體,因此子行程對資料段、堆或堆疊的任何改變將在父行程恢復執行時為其所見,此外,如果子行程在vfork()與后續的exec(或exit(之間執行了函式回傳,這同樣會影響到父行程,
例子:
1 #include<stdio.h> 2 #include<sys/types.h> 3 #include<unistd.h> 4 #include<sys/wait.h> 5 #include<stdlib.h> 6 #include<errno.h> 7 #include<string.h> 8 9 int main() 10 { 11 pid_t childPid; 12 if((childPid=vfork())==-1) 13 { 14 printf("Fork error %s\n",strerror(errno)); 15 exit(1); 16 } 17 else 18 if(childPid==0) //子行程 19 { 20 sleep(1); //子行程睡眠一秒 21 printf("I am the child : %d\n",getpid()); 22 exit(0); 23 } 24 else //父行程 25 { 26 printf("I am the father : %d\n",getpid()); 27 exit(0); 28 } 29 /* switch(childPid=vfork()){ 30 case -1: 31 printf("Fork error %s\n",strerror(errno)); 32 exit(1); 33 case 0: //子行程 34 sleep(1); //子行程睡眠一秒 35 printf("I am the child : %d\n",getpid()); 36 exit(0); 37 default: //父行程 38 printf("I am the father : %d\n",getpid()); 39 exit(0); 40 41 } */ 42 return 0; 43 }vfork_pid.c
結果:

運行程式時可以看到,程式會停一秒然后分別列印出父子行程的ID.也就是說子行程進來就阻塞一秒,但也沒有先去運行父行程,而是讓子行程運行完了之后才運行父行程,
參考資料
Linux/Unix系統編程手冊
Unix環境高級編程
Linux程式設計
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/83132.html
標籤:Linux
上一篇:開機提示藍牙檔案傳送
