【Linux】進程的基本屬性|父子進程關系

在這里插入圖片描述
在這里插入圖片描述

個人主頁:🍝在肯德基吃麻辣燙
我的gitee:Linux倉庫
個人專欄:Linux專欄
分享一句喜歡的話:熱烈的火焰,冰封在最沉默的火山深處

文章目錄

  • 前言
  • 進程屬性
    • 1.進程PID和PPID
    • 2.fork函數創建子進程
      • 1)為什么fork函數要給父進程返回子進程的pid,給子進程返回0?
      • 2)fork函數究竟在干什么?
      • 3)一個函數是如何做到返回兩次的?
        • 寫時拷貝
  • 總結


前言

本篇文章繼上文的進程概念后,現在對進程概念有了一定的理解。前面說過,操作系統管理進程實際上是管理描述進程的PCB對象,而PCB對象是一堆進程屬性的集合,那么進程都有哪些屬性?本篇文章會詳細寫出來。


進程屬性

我們知道,進程 = 描述該進程的PCB結構體對象 + 對應的數據和代碼,每一個進程都是由操作系統進行管理的,進程的PCB(process ctrl block)對象是該進程的所有屬性集合,所以,一個進程的多種屬性,一定是放在PCB結構體里面的。

下面介紹進程的基本屬性。


1.進程PID和PPID

什么是PID?PID我們可能不知道,但是ID我們應該是知道的,ID就是身份識別碼。所以PID就是進程身份識別碼(process ID)

在學校里面,每一個學生都有自己的學號,這個學號是獨一無二的,進程也是類似,每一個進程的PID是獨一無二的。

我們可以通過下面的指令來查看進程的PID。

ps axj | head -1

ps axj 指令可以查看當前用戶下的所有進程,通過管道后,head指令提取管道文件的第一行并輸出到顯示器中。
結果如下:

在這里插入圖片描述
第二個就是PID。

這里有一個注意的點,既然PID是該進程的唯一身份標識符,則該進程的PID一定是放在task_struct結構體中的,因為PID也是進程的屬性之一。PID的本質是一個int類型。


這里有一個問題:我如何獲取自己進程的PID?
在這里插入圖片描述
從上面的描述過程中可以畫出該圖,ps axj指令能獲取用戶正在運行的所有進程,這些進程的信息本質上是ps axj這條程序員寫的指令去調用操作系統開放的一個接口調用到的。

因為操作系統不相信任何人,它不敢也不給任何人訪問我的所有進程的PCB結構體和各種信息。

所以可以想到,要想獲取一個進程的PID,要通過一個系統調用接口來獲取,這個接口叫做getpid()

在這里插入圖片描述

下面來通過代碼讓操作系統給我們分配一個小小的進程:

  1 #include <stdio.h>2 #include <unistd.h>3 4 int main()5 {6     pid_t pid = getpid();7    8     while(1)9     {10                                                               11         printf("I am a process,my pid is %d\n",pid);12         sleep(1);13     }14 15     return 0;16 }

運行后,再查詢該進程的pid
在這里插入圖片描述
發現通過系統的接口函數返回的pid和我們運行程序時正在跑的進程的pid是一樣的

getpid()這個系統調用接口的工作原理是,我自己的進程調用getpid()函數,獲取到我的PID后將結果返回給上層的一個變量。

不過這又有一個小細節,PPID是什么?


PPID,比PID多了一個P,這個P是parent的意思,也就是父進程的PID。
父進程就是該進程的父親進程,就相當于我這個進程是父進程分配下來的。

我們再重新執行程序會發現,我原來的進程的PID變了。這就像是我們上大學后,發現我這個學校并不如意,我決定回去復讀,第二年我比去年多考了幾十分,可天意難料,我又被去年的學校錄取了。這個過程中,去年我讀的這所學校分配給我一個學號,今年再來到這所學校,也有一個學號,這兩個學號肯定是不一樣的。

那么,我們這樣通過寫代碼的方式創建一個進程,它的父進程到底是誰?
在這里插入圖片描述
我們查詢一下可以發現,每次執行程序,它的PID都不同,但是PPID都是一樣的,找到PID2215的那一行可以發現,它的COMMAND就是對應的進程對象。

由此可知,每一個自己創建的進程的父進程都是bash進程!
不過,bash進程的PID也是會變化的,重新啟動xhell腳本就得到不一樣的PID了。

2.fork函數創建子進程

fork函數的作用是:創建一個子進程。
在這里插入圖片描述
這里是fork函數的基本說明,然而,重要的是fork函數的返回值:

在這里插入圖片描述

  • 如果創建成功:返回子進程的pid給父進程,返回0給子進程。
  • 如果創建失敗,返回-1給父進程,子進程則什么都不返回。

下面給一段代碼演示一下fork函數。

  1 #include<stdio.h>                                                                                                                    2 #include<unistd.h>3 4 int main()5 {6     printf("begin:我是一個進程,我的pid是%d,我的ppid是%d\n",getpid(),getppid());7     pid_t id = fork();8 9     if(id == 0)10     {11         //子進程12          while(1)13          {14             printf("我是子進程,我的pid是%d,我的ppid是%d\n",getpid(),getppid());15             sleep(1);16          }17     }18 19     else if(id > 0)20     {21         //父進程22         while(1)23         {24             printf("我是父進程,我的pid是%d,我的ppid是%d\n",getpid(),getppid());25             sleep(1);26         }27     }28 29     return 0;30 }

在這里插入圖片描述

運行后你會發現結果如上:

執行第一個printf語句后,打印的pid和ppid就是當前正在運行進程的pid和ppid。

然后你會發現同時執行了if else if 兩個語句塊!

這到底是什么原因呢?

看運行結果可知,父進程的pid和ppid跟第一個printf打印出來的是一模一樣的!說明父進程就是當前這個程序的進程!而子進程是父進程的一個分支

這里還有幾個問題需要解決:


1)為什么fork函數要給父進程返回子進程的pid,給子進程返回0?

舉個簡單的例子,每一個孩子一定只有一個親生父親,但是每一個父親可能會有多個孩子,這是毋庸置疑的。假如一個父親有5個孩子,父親說:孩子,你過來。然后5個孩子齊刷刷地跑過來,父親到底叫的是哪個孩子呢?

所以就必須讓父進程知道每一個子進程的標識符!
也就是要知道每一個子進程叫什么名字,返回子進程的pid給父進程是最合理的。

而對于子進程來說,它的父進程只有一個且不花什么代價就能找到父進程pid,所以只需要返回0給子進程作為標識即可。


2)fork函數究竟在干什么?

要知道,fork函數的功能是創建一個子進程,可是到底什么叫做創建一個子進程?
其實,創建子進程,無非就是系統中多了一個進程!

我們知道,進程 = PCB數據結構 + 自己的代碼和數據,多一個進程就是在操作系統中多管理一個PCB數據結構和一段代碼罷了。

可是,子進程剛創建出來并沒有代碼和數據,所以子進程只能去找父進程的代碼和數據來執行。

在這里插入圖片描述
這就是為什么,fork函數之后的所有代碼是父子進程共享的!

這就解釋了從fork函數之后下面的代碼,父進程和子進程都能跑的原因。

那為什么要創建子進程?
因為在不同的場景中,我們需要讓父子進程執行不同的代碼塊!
前面我們說過,fork函數之后父子進程共享代碼,雖然是共享,實際上就是為了讓父子進程執行不同的代碼塊,完成不同的工作從而協調起來。


3)一個函數是如何做到返回兩次的?

前面說過,fork函數之后的代碼父子共享。 但是,fork函數,也是一個函數,是在系統內部實現的,調用的時候會在fork函數內部創建進程,大致會做幾件事情:

在這里插入圖片描述

1.創建子進程的PCB對象
2.初始化子進程的PCB
3.讓子進程指向父進程的數據和代碼
4.讓父子進程都能被CPU調度運行

前面說過,父子進程的代碼是共享的,所以在return id這條代碼,一定是父子共享的! 因為在return id語句執行之前,已經做好了創建子進程的工作。CPU可以單獨調用父子進程執行不同的工作。

所以return id這條語句被執行了兩次!

可是前面說過,子進程是沒有任何數據和代碼的,子進程的代碼也是人家父進程的,何況只有一個pid變量,該怎么接收兩個返回值呢?

這里引出一個進程的性質:

任何平臺下,任何一個進程在運行時,都具有獨立性!

如何理解獨立性?

我們在windows系統下面,我現在打開網頁版csdn和xhell還有qq,突然我的qq崩潰了,但這并不影響我的網頁運行,也不影響我在聽音樂,這就是獨立性,各個進程運行互不干擾

既然進程有獨立性,這就保證了每個進程之間不能有任何瓜葛,必須讓它們割裂!
所以,父子進程一定不能訪問同一份數據!

在這個前提下,子進程要想運行起來,必須要有自己的一份數據,所以,子進程只能想辦法把父進程的數據拷貝下來

這樣就能夠保證父子進程既能夠保持父子進程的代碼共享,又能保證父進程的數據不能被修改。保證父子共享代碼的同時,又保證了進程的獨立性。

可是,如果我的父進程有很多很多個變量,而子進程拷貝了父進程的數據,又不會去改這些變量,甚至不訪問這些變量,就會造成在內存中有兩份冗余的數據!為了解決這個問題,程序員想出一個好辦法:寫時拷貝

寫時拷貝

寫時拷貝是指:子進程在執行了return id這一條語句后,不會立刻去拷貝父進程的所有數據,而是先看子進程需要什么數據,再根據這些數據開辟需要的空間,這樣就能避免數據冗余的情況。

后續如果子進程還需要數據,操作系統再給子進程空間并拷貝過去即可。

在這里插入圖片描述

通過寫時拷貝,實現父子進程的獨立性,保證父進程的數據不會被修改,又能保證父子進程的代碼共享!

總結

1.本篇文章講述了進程的最基本的屬性:進程的PID和PPID,PID是每個進程獨有的標識序號,PPID是該進程的父進程的標識序號。
2.通過fork函數創建出來子進程。什么是創建子進程,以及給了一個案例,運行后發現了令人震驚的結果,提出了fork函數之后父子進程的代碼是共享的,但是每個進程都具有獨立性,父進程的數據絕對不能讓子進程修改,從而產生寫時拷貝的做法,來保證父子進程既能夠具有獨立性,也能讓父子進程代碼共享。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/39508.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39508.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39508.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言學習筆記---數據的存儲詳解

C語言程序設計筆記---015 C語言數據的存儲1、數據類型的意義1.1、unsigned與signed數據類型例程11.2、補碼與原碼相互轉換例程2 2、大小端的介紹2.1、大小端的例程12.2、大小端的例程2 --- 判斷當前編譯器環境屬于大端或小端 3、綜合練習題探究數據的存儲3.1、練習題13.2、練習…

自動化安裝系統(一)

系統安裝過程 加載boot loader加載啟動安裝菜單加載內核和initrd文件加載根系統運行anaconda的安裝向導 安裝光盤中與安裝相關的文件 安裝autofs啟動后會自動出現/misc目錄。 在虛擬機設置中添加CD/DVD&#xff0c;使用系統ISO文件&#xff0c;登錄系統后mount /dev/cdrom …

青翼科技自研2路250MSPS DA回放FMC子卡模塊

FMC150_V30是一款基于VITA57.1規范的2路125MSPS采樣率16位分辨率AD采集、2路250MSPS采樣率16位分辨率DA回放FMC子卡模塊。該模塊遵循VITA57.1規范&#xff0c;可直接與符合VITA57.1規范的FPGA載卡配合使用&#xff0c;板卡ADC器件采用ADI公司的AD9268芯片&#xff0c;板卡DAC器…

機器學習理論筆記(一):初識機器學習

文章目錄 1 前言&#xff1a;藍色是天的機器學習筆記專欄1.1 專欄初衷與定位1.2 本文主要內容 2 機器學習的定義2.1 機器學習的本質2.2 機器學習的分類 3 機器學習的基本術語4 探索"沒有免費的午餐"定理&#xff08;NFL&#xff09;5 結語 1 前言&#xff1a;藍色是天…

mac安裝vscode 配置git

1、安裝vscode 官網地址 下載mac穩定版安裝很慢的解決辦法 (轉自) mac電腦如何解決下載vscode慢的問題 選擇谷歌瀏覽器右上角的3個點&#xff0c;選擇下載內容&#xff0c;右鍵選擇復制鏈接地址&#xff0c;在新窗口粘貼地址&#xff0c; 把地址中的一段替換成下面的vscode.cd…

項目配置中心介紹

目錄 什么是配置中心 為什么要有配置中心 配置中心的做法&#xff08;讀取和通知&#xff09; 配置中心優點: 常用的配置中心中間件 什么是配置中心 配置中心就是用來管理項目當中所有配置的系統&#xff0c;也是微服務系統當中不可或缺的一部分。項目的配置文件不放到本地…

Servlet+JDBC實戰開發書店項目講解第四篇:登錄實現

ServletJDBC 實戰開發書店項目講解第四篇&#xff1a;登錄注冊實現 在本篇博客中&#xff0c;我們將繼續講解 ServletJDBC 實戰開發書店項目。這次我們將重點講解如何實現登錄和注冊功能。 1. 創建數據庫表 首先&#xff0c;我們需要在數據庫中創建兩個表&#xff0c;一個用…

[C++] 模板template

目錄 1、函數模板 1.1 函數模板概念 1.2 函數模板格式 1.3 函數模板的原理 1.4 函數模板的實例化 1.4.1 隱式實例化 1.4.2 顯式實例化 1.5 模板參數的匹配原則 2、類模板 2.1 類模板的定義格式 2.2 類模板的實例化 講模板之前呢&#xff0c;我們先來談談泛型編程&am…

Qt讀寫Excel--QXlsx編譯為靜態庫2

1、概述&#x1f954; 在使用QXlsx時由于源碼文件比較多&#xff0c;如果直接加載進項目里面&#xff0c;會增加每次編譯的時間&#xff1b; 直接將源碼加載進項目工程中&#xff0c;會導致項目文件非常多&#xff0c;結構變得更加臃腫&#xff1b; 所以在本文中將會將QXlsx編譯…

骨傳導耳機頭暈是怎么回事?骨傳導耳機好不好

骨傳導耳機在音頻傳輸上采用了不同于傳統耳機的方式。它們通過將聲音振動傳遞到顳骨&#xff0c;然后通過骨骼傳導到內耳&#xff0c;從而使用戶能夠聽到音樂或聲音。 然而&#xff0c;有些人在使用骨傳導耳機時可能會感到頭暈。這可能與以下幾個原因有關&#xff1a; 1、剛開…

prometheusalert區分告警到不同釘釘群

方法一 修改告警規則 - alert: cpu使用率大于88%expr: instance:node_cpu_utilization:ratio * 100 > 88for: 5mlabels:severity: criticallevel: 3kind: CpuUsageannotations:summary: "cpu使用率大于85%"description: "主機 {{ $labels.hostname }} 的cp…

99%的Python用戶都不知道的f-string隱秘技巧

f-string想必很多Python用戶都基礎性的使用過&#xff0c;作為Python3.6版本開始引入的特性&#xff0c;通過它我們可以更加方便地向字符串中嵌入自定義內容&#xff0c;但f-string真正蘊含的功能遠比大多數用戶知道的要豐富&#xff0c;今天我們就來一起get它們~ 「最基礎用法…

ajax解析

Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;是一種用于在不重新加載整個頁面的情況下與服務器交換數據的技術。它通過異步的方式發送請求和接收響應&#xff0c;能夠實現在后臺與服務器進行數據交互&#xff0c;然后更新頁面的部分內容&#xff0c;從而提升用…

【CI/CD】基于 Jenkins+Docker+Git 的簡單 CI 流程實踐(上)

基于 JenkinsDockerGit 的簡單 CI 流程實踐&#xff08;上&#xff09; 在如今的互聯網時代&#xff0c;隨著軟件開發復雜度的不斷提高&#xff0c;軟件開發和發布管理也越來越重要。目前已經形成一套標準的流程&#xff0c;最重要的組成部分就是 持續集成 及 持續交付、部署。…

GPU編程基礎-CUDA實現圖像處理

GPU編程基礎-CUDA實現圖像處理 1. 相關基礎概念1.1 Host和Device程序1.2 Kernel程序1.3 SIMT和SIMD1.4 GPU計算的 Occupancy指標1.5 GPU計算的基本流程2. GPU計算框架與過程說明3. 一個基于CUDA的圖像處理例子4. 一些報錯解決1. 相關基礎概念 1.1 Host和Device程序 在CPU上運行…

Effective C++學習筆記(7)

目錄 條款41&#xff1a;了解隱式接口和編譯多態條款42&#xff1a;了解typename的雙重意義條款43&#xff1a;學習處理模板化基類內的名稱條款44&#xff1a;將與參數無關的代碼抽離templates條款45&#xff1a;運用成員函數模板接受所有兼容類型條款46&#xff1a;需要類型轉…

opencv,opengl,osg,vulkan,webgL,opencL,cuda,osg,vtk,ogre的區別

OpenCV OpenCV是一個基于BSD許可&#xff08;開源&#xff09;發行的跨平臺計算機視覺和機器學習軟件庫&#xff0c;可以運行在Linux、Windows、Android和Mac OS操作系統上。 它輕量級而且高效——由一系列 C 函數和少量 C 類構成&#xff0c;同時提供了Python、Ruby、MATLAB等…

avue多選列表根據后端返回的某個值去判斷是否選中;avue-curd多選回顯

效果如上&#xff1a; getSiteList().then(res > {//列表數據this.siteData res.data.datathis.$nextTick(()>{this.siteData.forEach(item>{//業務條件if(item.configid&&item.configid!0&&item.configid>0){//符合條件時調用選中的方法this.$…

JAVASE---數組的定義與使用

數組的基本概念 什么是數組 數組是具有相同類型元素的集合&#xff0c;在內存中連續存儲。 1. 數組中存放的元素其類型相同 2. 數組的空間是連在一起的 3. 每個空間有自己的編號&#xff0c;起始位置的編號為0&#xff0c;即數組的下標 數組的創建及初始化 數組的創建 T[…

mybatis高級特性

文章目錄 數據庫事務管理批處理插件擴展持久化和ORM緩存機制 數據庫事務管理 通過注解方式&#xff1a; 在需要進行事務管理的方法上添加Transactional注解&#xff0c;該注解可以用于類或方法上。在配置文件中開啟事務管理器&#xff0c;并指定事務管理器的類型和連接池等相關…