進程創建(一)之 fork & vfork

一、進程創建(PCB、虛擬地址空間、頁表、數據(映射關係加載好))
1、fork

fork可以從已有的進程中創建出一個新進程也叫作子進程,原來的那個進程就叫做父進程。一般,fork創建出子進程後,子進程一般是和父進程代碼實現共享,數據實現寫時拷貝的。

進程調用fork,當控制轉移到內核中的fork代碼後,內核會(1)將分配新的內存塊和內核數據結構給子進程。(2)將父進程部分數據結構拷貝至子進程。(3)添加子進程到系統進程列表當中。(4)fork返回,開始調度器調度

  • fork的返回值:(這個我有在前面的博客中具體寫過原因,可以戳此鏈接:https://blog.csdn.net/apt1203jn/article/details/79779888
    (1)子進程返回0;(2)父進程返回子進程的pid

  • fork的常規用法:(1)一個父進程希望複製自己,使得父子進程同時執行不同的代碼段(eg:父進程等待客戶端請求,創建子進程來處理請求)。(2)一個進程要執行一個不同的程序(eg:子進程從fork返回之後,調用exec函數 )

  • 調用fork失敗的原因:(1)內存不夠(2)實際用戶的進程數超過了限制

2、vfork

vfork()創建子進程的特點:

* 子進程和父進程共享地址空間(fork的子進程具有獨立的地址空間)
* vfork保證子進程先運行,在它調用exec或(exit)之後父進程纔可能被調度運行         

測試用例:

(1)驗證一下vfork()創建出的子進程會先於它的父進程調度運行(讓子進程sleep一下使它的生命週期變長)

先寫Makefile

.OPHNY:test

test:test.c
        gcc -o test test.c

.OPHNY:clean
        clean:
            rm -f test

test.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 100;
int main()
{
      //pid_t id = fork();
      pid_t id = vfork();
      if (id == 0){
            printf("child, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), get    ppid(), g_val, &g_val);
            sleep(3);
            exit(1);
      }
      else if (id > 0){
            printf("father, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), ge    tppid(), g_val, &g_val);
            exit(2);
      }    
      return 0;
}

先來看一下調用fork()創建子進程的運行結果
這裏寫圖片描述
註釋掉fork(),看一下vfork()創建子進程之後的調度順序
運行結果:
這裏寫圖片描述
由圖可見,vfork() 創建的子進程會先運行,在子進程調用exit函數之後父進程纔可能被調度運行。
大家可以自行驗證一下,我沒有開另外的終端檢測,所以運行效果不是非常非常明顯,大家自己動手驗證一下哦!

(2)驗證父進程和子進程共用一塊地址空間
test.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 100;
int main()
{
      pid_t id = fork();
      //pid_t id = vfork();
      if (id == 0){
          printf("befor:child, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), getppid(), g_val, &g_val);

          g_val = 200;
          printf("after:child, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), getppid(), g_val, &g_val);

          sleep(1);
          exit(1);
      }
      else if (id > 0){
          printf("father, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), ge    tppid(), g_val, &g_val);
      }
      return 0;
}

注:Makefile文件同上一個

下面是用fork()創建子進程的運行結果
這裏寫圖片描述

於此可以看出,fork()創建出的子進程並沒有直接改變父進程的變量值,那麼vfork()創建出的子進程會不會改變父進程的變量值嘞?

下面放開vfork() 的註釋,看一下運行結果
這裏寫圖片描述
解析:
上圖結果可見子進程直接改變了父進程的變量值,這主要是因爲子進程在父進程的地址空間中運行。

發佈了55 篇原創文章 · 獲贊 9 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章