【Linux】進程(1)進程概念和進程狀態

🌟🌟作者主頁:ephemerals__

🌟🌟所屬專欄:Linux

目錄

前言

一、什么是進程

二、task_struct的內容

三、Linux下進程基本操作

四、父進程和子進程

1. 用fork函數創建子進程

五、進程狀態

1. 三種重要狀態

運行狀態

阻塞狀態

掛起狀態

2. 內核鏈表的理解

3. Linux的進程狀態

孤兒進程?

總結


前言

????????在學習 Linux 操作系統的過程中,進程是一個至關重要的概念。無論你是想了解系統的基礎操作,還是深入研究 Linux 內核,進程管理的理解都將為你打下堅實的基礎。進程不僅是操作系統資源管理的核心,也是實現多任務處理的關鍵所在。通過學習進程的創建、調度、同步等機制,你可以更好地掌握操作系統的運行原理,進而優化系統性能和解決實際問題。本文將從基礎知識入手,帶領大家逐步深入探索 Linux 中進程的各個方面,幫助你在 Linux 學習的道路上邁出堅實的第一步。

一、什么是進程

? ? ? ? ?進程有多種描述方式,例如:程序的運行實例、正在執行的程序、操作系統進行資源調配的基本單位等。不過,以上說法都太理論化,我們用程序運行的實際情況來描述進程。

? ? ? ? 一個程序在執行前,其二進制代碼和數據(變量、常量、堆棧數據等)需要加載到內存。當加載完成之后,操作系統就會為這一塊代碼和數據創建一個對應的PCB(也叫做進程控制塊,本質是一個存儲進程相關信息的結構體),其中存在一個內存指針,指向代碼和數據,便于訪問。

? ? ? ? 所以“進程”不僅僅包括了程序的運行實例,它也包括操作系統管理該進程的相關信息。簡而言之,“進程”是指PCB與程序代碼數據的集合操作系統根據PCB來跟蹤進程的執行狀態,方便對進程進行調度。

????????而當有多個程序需要執行時,操作系統就會為每一個程序的代碼和數據都創建一個對應的PCB(描述過程),再通過容器將所有的PCB串聯起來(組織過程)。此時,操作系統對于進程的管理即為對容器的增刪查改

需要注意:

在Linux下,PCB(進程控制塊)是一個叫做task_struct的結構體;進程的所有屬性都可以通過task_struct直接或間接地找到。

Linux下的task_struct之間通過雙向鏈表進行連接。

二、task_struct的內容

?task_struct有如下成員,用于表示進程各種狀態信息,以及訪問程序的代碼和數據:

  • 進程標識符(PID)--區別其他進程

  • 進程狀態信息

  • 優先級

  • 程序計數器

  • 內存指針--指向代碼和數據

  • 上下文數據

  • I/O狀態信息

  • 記賬信息

  • 其他信息

?之后的進程學習當中,我們將圍繞以上成員數據,學習進程的相關概念及操作

三、Linux下進程基本操作


C語言函數獲取當前進程標識符和父進程的標識符(PID):

getpid(); //返回當前進程標識符,返回值類型是pid_t
getppid(); //返回當前進程的父進程標識符

注意使用以上函數時,需要引頭文件<unistd.h>


使用指令查看當前所有進程:

ps ajx
ls /proc

根據程序名查看某個進程信息:

ps ajx | head -1 && ps ajx | grep (可執行程序名)

根據標識符查看進程文件:

ll /proc/(標識符)

示例:

我們可以重點關注一下圖中列舉出的兩個文件cwdexe

cwd指的是當前進程對應的可執行程序所在目錄;

exe指的是當前進程對應的可執行程序位置。


C語言函數修改當前進程所在路徑:

chdir("(路徑)");

注意使用該函數要引頭文件<unistd.h>


殺進程的兩種方式:

1. ctrl + c

2. 命令行輸入kill -9? (進程標識符)

四、父進程和子進程

? ? ? ? 一個進程通過系統調用創建出的另一個進程稱之為該進程的子進程,反之該進程稱為其父進程。在Linux下,我們在命令行輸入的命令都是Bash(命令行解釋器)的子進程。

1. 用fork函數創建子進程

? ? ? ? ?fork是一個系統調用,存在于頭文件<unistd.h>中,當執行fork函數之后,當前進程會創建一個子進程,后續的代碼會被父進程和子進程分別執行一次

代碼示例:

#include <stdio.h>
#include <unistd.h>int main()
{fork();printf("hello world\n");return 0;
}

運行結果:

注意:fork函數創建的子進程沒有自己的代碼和數據,雖然操作系統為其創建了PCB,但是其內存指針指向的還是父進程的代碼和數據。

?子進程在創建成功后,fork函數會給子進程返回0,給父進程返回子進程的PID。為什么會給父子進程不同的返回值呢?因為一個父進程可能會有多個子進程,給父進程返回子進程的PID,更方便父進程對子進程進行管理。而子進程如果想要知道父進程的PID,直接調用getppidh函數即可。另外,返回值不同可以配合分支語句讓父子進程執行不同的代碼。示例如下:

#include <stdio.h>
#include <unistd.h>int main()
{pid_t id = fork();if(id == 0)//子進程{printf("我是子進程,我的pid是%d\n", getpid());}else//父進程{printf("我是父進程,我的pid是%d\n", getpid());}return 0;
}

運行結果:

? ? ? ? 那么,為什么fork函數能夠做到返回兩個值呢?實際上fork函數在執行return語句之前,就已經創建好了子進程,此時就可以通過分支語句來區分給父進程和子進程的返回值。?

注意:雖然fork函數創建的子進程與父進程的代碼是共享的,但如果父子任何一方要修改其中的數據,那么操作系統就會將數據進行拷貝,此時父子就各自維護自己的數據,本質上修改的是拷貝的數據,不會影響另一方。這種狀況叫做寫時拷貝

五、進程狀態

? ? ? ? 對于不同的操作系統,進程狀態可能略有不同,但常見的大體上的進程狀態有如下幾種:創建、就緒、運行、阻塞、終止、掛起。我們介紹一下其中最重要的三點:運行狀態、阻塞狀態和掛起狀態

1. 三種重要狀態

運行狀態

? ? ? ? 首先要知道,一般情況下一個CPU維護一個進程調度隊列,該隊列中存放著一個個PCB,等待CPU對它們進行調度。而一個PCB在運行隊列中排隊時,就稱該進程處于運行狀態

阻塞狀態

? ? ? ? 當一個進程需要等待某種資源或設備(如鼠標、鍵盤等)就緒時,該進程就處于阻塞狀態。阻塞狀態的進程在代碼層面的體現是:PCB從運行隊列中移出,轉而進入設備的等待隊列當中

此時若設備準備就緒(如按下鍵盤),則操作系統會修改當前設備狀態,然后檢查等待隊列,將等待隊列中的PCB重新移動到運行隊列當中,該進程重新恢復運行狀態。

掛起狀態

? ? ? ? 當一個進程被暫停執行時,稱該進程處于掛起狀態。?那么它的具體體現是什么呢?

????????當內存空間較為吃緊時,操作系統會將一些暫時不需要使用的內存數據(如阻塞狀態的PCB控制的代碼和數據喚出到磁盤中的swap交換分區。此時等待隊列中的PCB不再維護該進程的代碼和數據,這樣的進程狀態叫做阻塞掛起

????????此時,若設備準備就緒,則操作系統就將swap交換分區中的代碼和數據重新喚入到內存中,給PCB維護,然后恢復到運行狀態。

????????當內存空間嚴重不足時,操作系統會將運行狀態的PCB控制的代碼和數據也喚出到swap交換分區。此時稱之為運行掛起


由這三種狀態在代碼層面的一部分具體體現,我們可以得出如下結論:進程狀態的變化表現之一就是PCB在不同的數據結構之間移動,變化本質是操作系統對數據結構的增刪查改

2. 內核鏈表的理解

? ? ? ? 之前提到,在Linux下,操作系統會使用雙向鏈表將PCB串聯起來,方便進程管理。那么為什么PCB還會出現在CPU維護的調度隊列當中呢?其實task_struct確實是同時出現在兩種數據結構當中的,它基于一種特殊的結構來實現:?

task_struct當中,將用于構成雙向鏈表的指針域封裝成一個結構體list_head,它的指針指向的是其他task_struct的list_head。那么既然指向另一個指針域,如何能訪問到task_struct的其他成員呢?這就需要用到結構體內存對齊的相關知識了:結構體的成員都是按照自身的對齊數進行存儲的,第一個成員變量的地址就是結構體的首地址。通過求出list_head相對于結構體第一個成員的偏移量,就能間接訪問結構體的其他成員。例如,如下表達式就可以表示next指針指向的list_head所在task_struct的首地址(其中links表示list_head的變量):

(struct task_struct*)(next - &((struct task_struct*)0->links))

將0強轉為task_struct*類型,求出成員links的地址,即為links的偏移量,然后用links的地址減去該偏移量,得出task_struct的首地址,再強轉為task_struct*類型,然后就可以訪問其他成員了。

? ? ? ? 而其他指針域也可以通過這種方式訪問task_struct的其余成員,但可以用不同的鏈接方式,形成不同的數據結構,這樣就實現了一個PCB同時存在于多種數據結構的壯舉。

3. Linux的進程狀態

? ? ? ? 相比于之前提到的操作系統大體上的進程狀態,Linux的進程狀態就顯得更加具體化。在Linux下,進程狀態本質是task_struct內的長整型變量,它有以下幾種進程狀態表示:

static const char *const task_state_array[] = {"R (running)", /*0 */"S (sleeping)", /*1 */"D (disk sleep)", /*2 */"T (stopped)", /*4 */"t (tracing stop)", /*8 */"X (dead)", /*16 */"Z (zombie)", /*32 */
};

R:運行狀態

S:休眠狀態(可中斷休眠)

D:深度睡眠狀態(不可中斷休眠)

進程處于深度睡眠狀態時,不可被殺。

T:暫停狀態--用戶手動暫停進程(如Ctrl + z)

t:追蹤狀態--調試過程中執行到斷點處,進程被暫停

x:死亡狀態

z:僵尸狀態--子進程在死亡之后,代碼和數據可以釋放,但其PCB不能直接釋放,需要被父進程讀取信息,讀取信息之前稱之為僵尸狀態。

注意:如果父進程一直都不讀取子進程的信息,那么僵尸狀態就會一直存在,PCB也會一直存在,這就導致了內存泄漏。

孤兒進程?

? ? ? ? 除了以上幾種狀態,進程還有一種特殊情況:孤兒進程。?當父進程先死亡,子進程就會被1號進程領養,成為新的父進程,此時該子進程就被稱作孤兒進程。

注:1 號進程(init 或 systemd) 是 Linux 系統中的第一個用戶態進程,負責初始化系統并管理其他進程。它由內核在系統啟動時創建,PID固定為 1。現代 Linux 主要使用 systemd 作為 1 號進程,提供服務管理、日志收集和系統控制功能,而早期系統則使用 sysvinit 或 upstart。如果 1 號進程崩潰,系統通常會進入不可用狀態,需要重啟。

? ? ? ? 那么為什么子進程會被1號進程領養呢?如果1號進程不領養它,則當子進程死亡后,沒有父進程讀取信息,就會造成內存泄漏

總結

? ? ? ? 通過本篇文章,我們學習了Linux進程的基礎知識,包括進程概念、task_struct 結構、進程狀態以及父子進程關系,希望這篇文章能幫助你更清晰地理解Linux進程的運行機制。如果你覺得博主講的還不錯,就請留下一個小小的贊在走哦,感謝大家的支持???

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

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

相關文章

lws-minimal-ws-server前端分析

index.html index.html是前端入口 <html><head><meta charsetutf-8 http-equiv"Content-Language" content"en"/><!-- 引入js --><script src"/example.js"></script></head><body><img s…

L1-7 統一命名規范(java)

你所在的公司剛剛招收了幾位程序員&#xff0c;然而這些程序員之前在不同的公司工作&#xff0c;所以他們習慣的變量命名規范可能存在差異&#xff0c;需要讓他們都習慣公司要求的命名規范&#xff0c;然而這樣可能會降低他們的工作效率。 你的上司找到了你&#xff0c;希望你…

Flexus應用服務器L實例、X實例以及ECS(彈性計算服務)之間的區別及其適用場景

為了更好地理解Flexus應用服務器L實例、X實例以及ECS&#xff08;彈性計算服務&#xff09;之間的區別及其適用場景&#xff0c;下面我將通過具體的例子來說明每種類型的使用情況。 1. Flexus L實例 特點: 針對高并發和負載均衡進行了優化。它可能包括更快的網絡接口、更高效…

WebRTC中音視頻服務質量QoS之RTT衡量網絡往返時延的加權平均RTT計算機制?詳解

WebRTC中音視頻服務質量QoS之RTT衡量網絡往返時延加權平均RTT計算機制?的詳解 WebRTC中音視頻服務質量QoS之RTT衡量網絡往返時延加權平均RTT計算機制?的詳解 WebRTC中音視頻服務質量QoS之RTT衡量網絡往返時延加權平均RTT計算機制?的詳解前言一、 RTT 網絡往返時延的原理?1、…

odbus TCP轉Modbus RTU網關快速配置案例

Modbus TCP 轉Modbus RTU網關快速配置案例 在工業自動化領域&#xff0c;Modbus 協議以其簡潔和高效而著稱&#xff0c;成為眾多設備通信的首選。 隨著技術的發展和應用場景的變化&#xff0c;Modbus 協議也發展出了不同的版本&#xff0c;其中 Modbus TCP 和 Modbus RTU 是兩種…

《高效遷移學習:Keras與EfficientNet花卉分類項目全解析》

從零到精通的遷移學習實戰指南&#xff1a;以Keras和EfficientNet為例 一、為什么我們需要遷移學習&#xff1f; 1.1 人類的學習智慧 想象一下&#xff1a;如果一個已經會彈鋼琴的人學習吉他&#xff0c;會比完全不懂音樂的人快得多。因為TA已經掌握了樂理知識、節奏感和手指…

WSL2 Ubuntu安裝GCC不同版本

WSL2 Ubuntu安裝GCC不同版本 介紹安裝gcc 7.1方法 1&#xff1a;通過源碼編譯安裝 GCC 7.1步驟 1&#xff1a;安裝編譯依賴步驟 2&#xff1a;下載 GCC 7.1 源碼步驟 3&#xff1a;配置和編譯步驟 4&#xff1a;配置環境變量步驟 5&#xff1a;驗證安裝 方法 2&#xff1a;通過…

淘寶API vs 爬蟲:合規獲取實時商品數據的成本與效率對比

以下是淘寶 API 和爬蟲在合規獲取實時商品數據方面的成本與效率對比&#xff1a; 成本對比 淘寶 API 開發成本&#xff1a;需要申請開發者賬號并獲取 API 權限&#xff0c;部分敏感或高頻訪問的接口可能需要額外的審核或付費。開發過程中需要按照平臺規定進行編程&#xff0c;相…

Android 手機啟動過程

梳理 為了梳理思路&#xff0c;筆者畫了一幅關于 Android 手機啟動的過程圖片內容純屬個人見解&#xff0c;如有錯誤&#xff0c;歡迎各位指正

【Linux】:封裝線程

朋友們、伙計們&#xff0c;我們又見面了&#xff0c;本期來給大家帶來封裝線程相關的知識點&#xff0c;如果看完之后對你有一定的啟發&#xff0c;那么請留下你的三連&#xff0c;祝大家心想事成&#xff01; C 語 言 專 欄&#xff1a;C語言&#xff1a;從入門到精通 數據結…

正則表達式全解析 + Java常用示例

目錄 一、正則表達式基礎&#xff08;一&#xff09;元字符&#xff08;二&#xff09;字符集&#xff08;三&#xff09;量詞 二、正則表達式常用示例&#xff08;一&#xff09;驗證郵箱格式&#xff08;二&#xff09;驗證電話號碼格式&#xff08;三&#xff09;提取網頁中…

LoRa數傳、點對點通信、Mesh網絡、ZigBee以及圖傳技術的區別和特點

以下是LoRa數傳、點對點通信、Mesh網絡、ZigBee以及圖傳技術的區別和特點&#xff1a; 1.LoRa數傳? 特點&#xff1a;LoRa是一種基于擴頻技術的低功耗廣域網&#xff08;LPWAN&#xff09;通信技術&#xff0c;具有傳輸距離遠&#xff08;城市環境可達2-5公里&#xff0c;鄉村…

星越L_三角指示牌及危險警示燈使用

目錄 1.打開危險警告燈 2.取出反光背心穿上 3.取出指示牌 4.放置三角指示牌。 1.打開危險警示燈 2.取出反光背心穿上 3.取出指示牌

AI與人的智能,改變一生的思維模型【7】易得性偏差

目錄 **易得性偏差思維模型&#xff1a;大腦的「熱搜算法」與反操縱指南****病毒式定義&#xff1a;你的大腦正在被「熱搜」劫持****四大核心攻擊路徑與史詩級案例****1. 信息過載時代的「認知短路」****2. 媒體放大器的「恐怖濾鏡」****3. 個人經驗的「數據暴政」****4. 社交繭…

Jmeter的簡單使用

前置工作 確保java8 版本以上jmeter下載路徑&#xff08;選擇Binaries&#xff09;&#xff1a;https://jmeter.apache.org/download_jmeter.cgi直接解壓&#xff0c;找到bin下面的文件&#xff1a;jmeter.bat&#xff08;可選&#xff09;漢化&#xff0c;修改 jmeter.proper…

MyBatis源碼分析の配置文件解析

文章目錄 前言一、SqlSessionFactoryBuilder1.1、XMLConfigBuilder1.2、parse 二、mappers標簽的解析2.1、cacheElement2.1.1、緩存策略 2.2、buildStatementFromContext2.2.1、sql的解析 前言 本篇主要介紹MyBatis源碼中的配置文件解析部分。MyBatis是對于傳統JDBC的封裝&…

golang快速上手基礎語法

變量 第一種&#xff0c;指定變量類型&#xff0c;聲明后若不賦值&#xff0c;使用默認值0 package mainimport "fmt"func main() {var a int //第一種&#xff0c;指定變量類型&#xff0c;聲明后若不賦值&#xff0c;使用默認值0。fmt.Printf(" a %d\n"…

Java中的訪問修飾符有哪些

在 Java 中&#xff0c;訪問修飾符&#xff08;Access Modifiers&#xff09;用于控制類、方法、變量和構造器的訪問權限。Java 提供了四種訪問修飾符&#xff0c;分別是&#xff1a; publicprotecteddefault&#xff08;包私有&#xff0c;沒有顯式修飾符&#xff09;private…

【公務員考試】高效備考指南

高效備考指南&#xff1a;從計劃制定到心態調整的全面攻略 公務員考試競爭激烈&#xff0c;備考過程既需要科學規劃&#xff0c;也需要持之以恒的努力。結合多位高分考生的經驗與專業機構的指導&#xff0c;本文整理了一套系統化的備考策略&#xff0c;涵蓋目標設定、學習方法…

工程實踐:如何使用SU17無人機來實現室內巡檢任務

阿木實驗室最近發布了科研開發者版本的無人機SU17&#xff0c;該無人機上集成了四目視覺&#xff0c;三維激光雷達&#xff0c;云臺吊艙&#xff0c;高算力的機載計算機&#xff0c;是一個非常合適的平臺用于室內外巡檢場景。同時阿木實驗室維護了多個和無人機相關的開源項目。…