最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解Linux中的fork機制

 更新時間:2025年03月17日 09:30:45   作者:.17.  
fork() 是一種系統(tǒng)調用,用于在操作系統(tǒng)中創(chuàng)建新進程,當 fork() 被調用時,會生成一個當前進程的副本(稱為子進程),而原始進程則被稱為父進程,本文給大家詳細介紹了Linux中的fork機制,需要的朋友可以參考下

前言

在Linux系統(tǒng)中,進程是操作系統(tǒng)最重要的執(zhí)行單元,而父子進程的創(chuàng)建與管理更是系統(tǒng)資源分配和任務并行的關鍵。通過fork函數,Linux能夠快速高效地復制一個進程,使得父子進程協(xié)同工作成為可能。理解父子進程的運行機制不僅有助于掌握系統(tǒng)編程的核心技能,更能為優(yōu)化資源利用與提高程序性能提供理論基礎。本文將帶你從基礎原理出發(fā),解析Linux父子進程的運行特性、fork的核心機制及其在實際開發(fā)中的應用。

一、進程PID

PID 是用來唯一標識一個進程的屬性,我們可以使用 ps 指令查看一個進程的部分屬性。進程的屬性信息是由操作系統(tǒng)來維護的,這些信息被存儲在一個 task_struct 結構體中,屬于操作系統(tǒng)內核中的數據。由于操作系統(tǒng)本身是不相信用戶的,所以用戶無法直接去訪問 task_struct 對象中的成員,因此 ps 指令能夠顯示進程的屬性信息,本質上是通過系統(tǒng)調用接口去實現的。

1.1 通過系統(tǒng)調用接口查看進程PID

獲取進程的 PID 需要用到系統(tǒng)調用接口 getpid() ,該函數會返回調用該函數的進程的 PID,返回值類型為 pid_t 。如下圖我們使用 man getpid 指令去查看 getpid 的基礎文檔:

在這里插入圖片描述

注意上圖中還有一個 getppid 是什么呢?不難猜到,這應該是用來獲取父進程 PID 的系統(tǒng)調用接口,接下來我們寫段代碼來具象化 PID 吧。

注意上圖中還有一個 getppid 是什么呢?不難猜到,這應該是用來獲取父進程 PID 的系統(tǒng)調用接口,接下來我們寫段代碼來具象化 PID 吧。

#include <stdio.h>    
#include <unistd.h>    
#include <sys/types.h>    

int main()    
{    
    while(1)    
    {    
        printf("I am a process, my id is: %d, parent id is: %d\n", getpid(), getppid());                                  
        sleep(1);    
    }    
    return 0;    
}

我們可以寫一個腳本來實時獲取上面這段代碼執(zhí)行起來后的進程信息。

在這里插入圖片描述

在這里插入圖片描述

可以看到,我一個將這段代碼執(zhí)行了兩次,每一次的子進程 PID 都在發(fā)生變化,但是父進程的 PID 從未更改。

為了保證數據的準確性,我們再使用 ps 指令對比以下獲取到的進程 PID 是否真的一樣。

while :; do ps axj | head -1 ; ps axj |grep process | grep -v grep ;  sleep 1 ; done

在這里插入圖片描述

在這里插入圖片描述

結論:我們用 getpidgetppid 得到的父子進程的 PIDps 指令獲取到的進程 PID 是一樣的

二、通過系統(tǒng)調用創(chuàng)建進程-fork初識

之前我們自己創(chuàng)建進程都是通過寫一份源代碼,然后去編譯運行,最終得到一個進程,今天給大家介紹另一種通過系統(tǒng)調用接口 fork 去創(chuàng)建進程的方式。一樣的,我們使用 man fork 去查看一下 fork 的相關文檔:

在這里插入圖片描述

大致意思就是:fork 函數會以調用該函數的進程作為父進程去創(chuàng)建一個子進程.

在這里插入圖片描述

創(chuàng)建成功時,會在父進程中返回子進程的 PID ,在子進程中返回 0 。否則就在父進程中返回 -1 ,子進程創(chuàng)建失敗。

2.1 調用fork函數后的現象

#include <stdio.h>      
#include <unistd.h>      
#include <sys/types.h> 
int main()                                                           
{    
    printf("before:only one line\n");    
    fork();    
    printf("after:only one line\n");    
    
    return 0;    
}

在這里插入圖片描述

如上圖所示,fork 后面的代碼執(zhí)行了兩次!這是什么原因呢?我們再寫一段代碼跑跑。

#include <stdio.h>      
#include <unistd.h>      
#include <sys/types.h> 

int main()    
{    
    printf("begin:我是一個進程,pid:%d, ppid:%d\n",getpid(), getppid());    
    
    pid_t id = fork();    
    if(id > 0)    
    {    
        while(1)    
        {    
            printf("我是父進程,pid:%d,ppid:%d\n",getpid(),getppid());    
            sleep(1);    
        }    
    }    
    else if(id == 0)    
    {    
        while(1)    
        {    
            printf("我是子進程,pid:%d,ppid:%d\n",getpid(),getppid());    
            sleep(1);    
        }    
    }    
    else    
    {    
        perror("子進程創(chuàng)建失?。n");    
    } 
    
    return 0;    
}

在這里插入圖片描述

通過結果我們可以得出,在上面的一份代碼中 id 大于0和 id 等于0同時存在, ifelse if 同時滿足,并且有兩個死循環(huán)在同時跑。這個現象說明此時一定存在兩個進程,即原來的 myprocess 進程和在 myprocess 進程中創(chuàng)建的子進程,因為在一個進程中 ifelse if 是不可能同時滿足的。這也符合 fork 函數創(chuàng)建子進程的目的,fork 函數創(chuàng)建子進程后,會從原來的一個執(zhí)行流變成兩個執(zhí)行流。

2.2 為什么fork要給子進程返回0,給父進程返回子進程 pid?

1. fork 返回值的設計目的

fork 是 UNIX 系統(tǒng)中用于創(chuàng)建新進程的核心系統(tǒng)調用。調用一次 fork,系統(tǒng)會“分 裂”出兩個進程:父進程和子進程。它的返回值有以下特點:

  • 在父進程中fork 返回新創(chuàng)建的子進程的 PID,使得父進程可以通過該 PID 來管理和操作子進程(如使用 waitkill 等操作)。
  • 在子進程中fork 返回 0,標識自己是子進程,無需再通過 PID 區(qū)分。

這種設計的核心目的正如您提到的,用于區(qū)分不同執(zhí)行流,即便父子共享同一套代碼,也可以根據返回值選擇性地執(zhí)行不同代碼。

2. 現實類比的深入解讀

  • 父親喊“兒子”:如果不區(qū)分,所有子進程都會響應,導致混亂。通過分配唯一的 PID,每個子進程可以被單獨識別。
  • 子進程喊“爸爸”:由于每個子進程只能有一個父進程,所以子進程通過調用 getppid() 即可找到其唯一的父進程。

3. 為什么子進程返回值為 0

  • 簡單區(qū)分:子進程無需知道自己的 PID 來執(zhí)行自己的任務,而只需通過返回值 0 知道自己是子進程。效率和邏輯一致性:如果子進程也返回自己的 PID,會引入額外的復雜性,而且父進程需要一個單獨機制區(qū)分這些值。

2.3 一個函數是如何做到返回兩次的?如何理解?

在調用 fork 函數之前就只有一個進程,我們先來回顧一下什么是進程?進程 = 內核數據結構 + 代碼和數據,其中的內核數據結構就是進程對應的 PCB 對象。

在這里插入圖片描述

進程的 PCB 對象會找到相應的代碼和數據,然后 CPU 就要去調度這個進程,也就是找到該進程的代碼和數據去執(zhí)行。調用 fork 函數創(chuàng)建子進程,本質上是操作系統(tǒng)多了一個進程,因此 fork 函數創(chuàng)建出來的子進程,它要先創(chuàng)建自己的 PCB 對象,子進程的 PCB 對象大部分都是以父進程的 PCB 對象為模板創(chuàng)建的,即從父進程的 PCB 對象中拷貝過來,再對部分屬性稍作修改,子進程的 PCB 對象就有了。但是它沒有自己的代碼和數據,所以只能用父進程的,所以 fork 函數之后,父子進程的代碼共享,這就解釋了為什么上面 fork 函數之后的代碼輸出了兩次,其實就是父子進程各自執(zhí)行了一次。

創(chuàng)建子進程的目的就是為了幫助父進程做不同的事情,但是父子進程共享一份代碼,所以我們應該在代碼中對它們加以區(qū)分。fork 函數就幫我們完成了這個需求,它會在父子進程中返回不同的值,用戶只需要根據返回值的不同讓父子進程執(zhí)行不同的代碼。
fork 函數的實現過程:

pid_t fork():

  • 創(chuàng)建子進程
  • 創(chuàng)建子進程的PCB
  • 填充PCB對應的內容
  • 讓子進程和父進程指向同樣的代碼
  • 此時父子進程都有獨立的task_struct對象,可以被CPU調度運行了
  • return ret;

由于父子進程會共享一份代碼,所以在 fork 函數執(zhí)行 return 語句之前,子進程的 PCB 對象就已經被創(chuàng)建出來了,CPU 已經可以去同時調度父子進程。由于 fork 函數中的 return 語句也是被共享的,所以 fork 函數有兩個返回值。

2.4 一個變量怎么會有不同的內容?

1. fork 的返回值如何寫入不同的變量空間

當調用 fork 時,父進程與子進程會各自接收一個返回值,并且寫入同名變量 id。但這并不意味著他們共享同一塊內存,而是因為:

  • 獨立的進程地址空間
    每個進程都有自己獨立的虛擬地址空間。在 fork 之后,父進程與子進程的地址空間是彼此獨立的。盡管子進程初始時看起來與父進程完全相同,但實際上它們的數據是分離的。
  • 寫時拷貝(COW)機制
    操作系統(tǒng)為提高效率并節(jié)省資源,采用了寫時拷貝技術。在 fork 之后:
    • 父子進程共享同一份內存數據,直到有一方嘗試修改這些數據。
    • 當某個進程試圖修改數據時,操作系統(tǒng)會為該進程分配新的物理內存空間,并將被修改的數據復制到新分配的空間中。

2. fork 中變量 id 的本質

在代碼中,變量 id 是存儲 fork 返回值的地方。以下幾點解釋了為什么同名變量可以存儲不同的值:

  • 父子獨立運行
    fork 返回后,父子進程的執(zhí)行路徑分開。父進程的 id 變量存儲的是子進程的 PID,而子進程的 id 變量存儲的是 0。
  • 不同的內存空間
    由于父子進程的地址空間獨立,id 實際上存在于兩塊不同的內存區(qū)域,即父進程的 id 和子進程的 id完全獨立的變量。
  • 賦值過程
    fork 的返回值通過操作系統(tǒng)寫入到父子進程各自的 id 變量中: 父進程在 return 時向 id 寫入子進程的 PID。子進程在 return 時向 id 寫入 0。

結語

Linux父子進程的運行機制展示了操作系統(tǒng)設計的高效性與靈活性。從fork的返回值設計到寫時拷貝(COW)的優(yōu)化方案,這一切都體現了Linux在性能與資源利用上的巧妙平衡。通過深入理解父子進程的特性,不僅能夠提升系統(tǒng)編程的能力,還能為并發(fā)和并行程序設計提供堅實的理論支持。希望本文能為你的學習和實踐帶來啟發(fā),在Linux系統(tǒng)的探索中邁向更高的層次。

以上就是一文詳解Linux中的fork機制的詳細內容,更多關于Linux fork機制的資料請關注腳本之家其它相關文章!

相關文章

  • CentOS8 yum/dnf 配置國內源的方法

    CentOS8 yum/dnf 配置國內源的方法

    這篇文章主要介紹了CentOS8 yum/dnf 配置國內源的方法,需要的朋友可以參考下
    2019-10-10
  • Linux之ipmitool管理BMC詳解

    Linux之ipmitool管理BMC詳解

    這篇文章介紹了ipmitool的基本用法和一些常用的命令,包括獲取傳感器信息、顯示系統(tǒng)信息、電源控制、顯示事件日志和啟用/禁用BMC用戶等,還介紹了如何通過IPMI-over-LAN遠程控制BMC,并提供了連接到遠程BMC的基本步驟
    2024-11-11
  • CentOS 7.2配置Apache服務httpd(下)

    CentOS 7.2配置Apache服務httpd(下)

    這篇文章主要為大家詳細介紹了CentOS 7.2配置Apache服務 httpd上篇,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • CentOS7yum安裝PHP7.2的操作方法

    CentOS7yum安裝PHP7.2的操作方法

    下面小編就為大家分享一篇CentOS7yum安裝PHP7.2的操作方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-03-03
  • 升級Linux系統(tǒng)內核的三種實現方法

    升級Linux系統(tǒng)內核的三種實現方法

    在現代?IT?基礎設施中,Linux?內核作為操作系統(tǒng)的核心,其穩(wěn)定性、安全性和性能直接影響整個系統(tǒng)的運行效率,本篇博客將帶你從零開始,全面了解如何安全、高效地升級?Linux?內核,需要的朋友可以參考下
    2026-03-03
  • Linux新磁盤到擴容到已有目錄方式

    Linux新磁盤到擴容到已有目錄方式

    文章詳細描述了一個服務器磁盤掛載和擴容的過程,包括添加磁盤、查看掛載情況、創(chuàng)建分區(qū)、格式化分區(qū)、擴展卷組和邏輯卷,并最終同步文件系統(tǒng)
    2026-03-03
  • .httacces文件的配置技巧

    .httacces文件的配置技巧

    我要介紹的.htaccess的第一個應用是自定義錯誤頁面,這將使你可以擁有自己的、個性化的錯誤頁面(例如找不到文件時),而不是你的服務商提供的錯誤頁或沒有任何頁面。
    2008-06-06
  • CentOS 7配置LNMP開發(fā)環(huán)境及配置文件管理詳解

    CentOS 7配置LNMP開發(fā)環(huán)境及配置文件管理詳解

    本篇文章主要介紹了CentOS 7配置LNMP開發(fā)環(huán)境及配置文件管理,詳細的介紹了MySQL 5.6,PHP 5.6,Nginx的安裝與配置,有興趣的可以了解一下。
    2017-01-01
  • linux運行vue編譯后的項目方式

    linux運行vue編譯后的項目方式

    這篇文章主要介紹了linux運行vue編譯后的項目方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2026-03-03
  • Linux中進程和線程的對比與區(qū)別

    Linux中進程和線程的對比與區(qū)別

    這篇文章主要介紹了Linux中進程和線程的對比與區(qū)別的相關資料,需要的朋友可以參考下
    2017-07-07

最新評論

新田县| 金坛市| 昭苏县| 张家界市| 鄂伦春自治旗| 华宁县| 岑溪市| 台前县| 蕲春县| 噶尔县| 双江| 冕宁县| 忻城县| 上饶市| 陈巴尔虎旗| 许昌市| 呼和浩特市| 普宁市| 洪湖市| 游戏| 新野县| 称多县| 蚌埠市| 华蓥市| 瓦房店市| 吉安市| 蓬安县| 霞浦县| 长岭县| 鄱阳县| 上饶县| 邹平县| 三门峡市| 皋兰县| 开江县| 平度市| 万载县| 济宁市| 泗水县| 句容市| 栾城县|