进程之父子进程的关系
轉載:https://blog.csdn.net/qq_28840229/article/details/79844763
fork之后:
父子相同處: 全局變量、.data、.text、棧、堆、環境變量、用戶ID、宿主目錄、進程工作目錄、信號處理方式...
父子不同處: 1.進程ID ??2.fork返回值 ??3.父進程ID ???4.進程運行時間 ???5.鬧鐘(定時器) ??6.未決信號集
似乎,子進程復制了父進程0-3G用戶空間內容,以及父進程的PCB,但pid不同。真的每fork一個子進程都要將父進程的0-3G地址空間完全拷貝一份,然后在映射至物理內存嗎?
當然不是!父子進程間遵循讀時共享寫時復制的原則。這樣設計,無論子進程執行父進程的邏輯還是執行自己的邏輯都能節省內存開銷。
1、fork函數時調用一次,返回兩次。在父進程和子進程中各調用一次。子進程中返回值為0,父進程中返回值為子進程的PID。程序員可以根據返回值的不同讓父進程和子進程執行不同的代碼。子進程是父進程的副本,獲得了父進程數據空間、堆和棧的副本;父子進程并不共享這些存儲空間,共享正文段(即代碼段);因此子進程對變量的所做的改變并不會影響父進程。一般來說,fork之后父、子進程執行順序是不確定的,這取決于內核調度算法。進程之間實現同步需要進行進程通信。
子進程對數據進行減一操作,父進程做加一操作:
#include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 ?
 int main()
 {
 ?pid_t pid;
 ?char *message;
 ?int n = 0;
 ?pid = fork();
 ?while(1){
 ?if(pid < 0){
 ?perror("fork failed\n");
 ?exit(1);
 ?}
 ?else if(pid == 0){
 ?n--;
 ?printf("child's n is:%d\n",n);
 ?}
 ?else{
 ?n++;
 ?printf("parent's n is:%d\n",n);
 ?}
 ?sleep(1);
 ?}
 ?exit(0);
 }
 2、進程等待
孤兒進程:?父進程生成子進程,但是父進程比子進程先結束;子進程會變成孤兒進程,由系統1號init 進程進行接管。init 進程接管后,在該孤兒進程結束的時候,負責“收尸”,回收系統資源及進程信息。
僵尸進程:子進程已經退出,但是沒有父進程回收它的資源(父進程生成的子進程,但是子進程比父進程先掛掉,如果父進程沒有收回它的資源時,那么子進程掛掉后就變成了僵尸進程;應該盡量避免產生僵尸進程,可以在父進程調用wait 或者waitpid 進程回收)。
進程一旦調用了wait,就立即阻塞自己,由wait 自動分析是否當前進程的某個子進程已經退出。如果讓它找到了這樣一個已經變成僵尸的子進程,wait 就會收集這個子進程的信息,并把它徹底銷毀后返回;如果沒有找到這樣一個子進程,wait 就會一直阻塞在這里,直到有一個出現為止。
補充:
 進程0
內核是一個大的程序,可以控制硬件,也可以創建、運行、終止、控制所有的進程。當內核被加載到內存后,首先就會有完成內核初始化的函數start_kernel()從無到有的創建一個內核線程swap,并設置其PID為0,即進程0;它也叫閑逛進程;進程0執行的是cpu_idle()函數,該函數僅有一條hlt匯編指令,就是在系統閑置時用來降低電力的使用和減少熱的產生。同時進程0的PCB叫做init_task,在很多鏈表中起了表頭的作用。
當就緒隊列中再沒有其他進程時,閑逛進程就會被調度程序選中,以此來省電,減少熱量的產生。
進程1
即init進程。首先內核線程kernel_init執行內核的一些初始化函數,以將內核初始化。那么此內核態的線程又是怎樣變為一個用戶進程的?實際上,kernel_int()內核函數中調用了execve()系統調用,該系統調用裝入用戶態下的一個可執行程序init,從而啟動用戶進程init進程。注意,內核函數kernel_init()與用戶態下的可執行文件init是不同的,位置不同,運行狀態不同,代碼也不同。init進程只是內核線程kernel_init啟動起來的一個普通的用戶進程,當然也是用戶態下的第一個進程,并且init進程從不終止,用來創建和監控操作系統外層的所有進程的活動。
 3、父進程創建多個子進程問題
void createsubprocess(int num) ?
 { ?
 ? ? pid_t pid; ?
 ? ? int i; ?
 ? ? for(i=0;i<num;i++) ?
 ? ? { ?
 ? ? ? ? pid=fork(); ?
 ? ? ? ? if(pid==0||pid==-1) ?//子進程或創建進程失敗均退出,這里是關鍵所在,子進程中跳出循環。
 ? ? ? ? { ?
 ? ? ? ? ? ? break; ?
 ? ? ? ? } ?
 ? ? } ?
 ? ? if(pid==-1) ?
 ? ? { ?
 ? ? ? ? perror("fail to fork!\n"); ?
 ? ? ? ? exit(1); ?
 ? ? } ?
 ? ? else if(pid==0) ?
 ? ? { ?
 ? ? ? ? printf("子進程id=%d,其對應的父進程id=%d\n",getpid(),getppid()); ?
 ? ? ? ? exit(0); ?
 ? ? } ?
 ? ? else?
 ? ? { ?
 ? ? ? ? printf("父進程id=%d\n",getpid()); ?
 ? ? ? ? exit(0); ?
 ? ? } ?
 }
總結
以上是生活随笔為你收集整理的进程之父子进程的关系的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 多态情况下,怎么用基类指针去访问基类的虚
 - 下一篇: Tomcat优化技巧