Linux | 進程概念、進程狀態(僵尸進程、孤兒進程、守護進程)、進程地址空間

文章目錄

  • 進程和程序
  • 操作系統如何控制和調度程序
  • 進程控制塊–PCB
  • 子進程
  • 進程狀態
    • 僵尸進程
    • 孤兒進程
    • 守護進程(精靈進程)
  • 進程地址空間
    • 引言
    • 頁表


進程和程序

  • 程序: 一系列有序的指令集合(就是我們寫的代碼)。
  • 進程: 進程就是程序的一次執行,是系統進行資源分配和調度的獨立單位。

一個程序可以創建多個進程,每個進程的文本段相同,但是數據段、堆、堆棧段卻不同。

進程的特性:

  • 動態性:進程是動態的;程序則是靜態的。
  • 并發性:多個進程能在同一時間段內同時運行。
  • 獨立性:系統中獨立獲得資源和進行調度的基本單位。
  • 異步性:各進程按不可預知的速度各自運行。

程序最初以某種可執行格式駐留在外存上(如:磁盤)。操作系統運行程序時將需要用到的代碼和所有靜態數據加載(load)到內存中(惰性執行,暫時用不到的代碼不加載),方便 CPU 運行進程時使用。
在這里插入圖片描述


操作系統如何控制和調度程序

實際中,一個正常的系統可能會有上百個進程同時在運行,而我們只有少量的物理 CPU 可以使用,因此,如何滿足諸多進程對于 CPU 的需求便成了重中之重。

按照馮諾依曼體系結構,所有的數據想要被CPU進行處理,第一步就是要將代碼和數據加載到內存中。
在這里插入圖片描述

操作系統通過 虛擬化CPU ,讓一個進程只運行一個時間片,然后切換到其他進程,通過 快速切換優先級調度 運行所有的程序,造成了同時運行的假象。這就是 時分共享CPU技術 ,也就是 CPU分時機制

但是,這里還存在著幾個問題,CPU是如何在內存中找到每個程序的?CPU在來回調度時,如何能夠從上一次運行的位置繼續運行?如何能夠保證繼續處理上一條沒有處理完的數據?

操作系統為了能夠完成上述操作,設置了一個用于描述進程信息的數據結構—— PCB


進程控制塊–PCB

操作系統為了能夠使每個程序能夠獨立運行,在操作系統中為其配置了一個數據結構,也就是我們通常所說的 PCB(Process Control Block),這個數據結構在 Linux下是:task_struct

task_struct 中的內容:

  • 標示符: 描述本進程的唯一標示符,用來區別其他進程。
  • 狀態: 任務狀態,退出代碼,退出信號等。
  • 優先級: 相對于其他進程的優先級。
  • 程序計數器: 程序中即將被執行的下一條指令的地址。
  • 內存指針: 包括程序代碼和進程相關數據的指針,還有和其他進程共享的內存塊的指針。
  • 上下文數據: 進程執行時處理器的寄存器中的數據。
  • I/O狀態信息: 包括顯示的I/O請求,分配給進程的I/O設備和被進程使用的文件列表。
  • 記賬信息: 可能包括處理器時間總和、使用的時鐘數總和、時間限制、記賬號等其他信息。

在這里插入圖片描述

PCB有兩種組織方式:

  • 鏈接方式:將同一狀態的進程PCB鏈成一個隊列,多個狀態對應多個不同的隊列。
  • 索引方式:將同一狀態的進程歸入一個索引表,多個狀態對應多個不同的索引。

鏈接方式:
在這里插入圖片描述
索引方式:
在這里插入圖片描述

PCB是操作系統對一個運行中的程序(也就是進程)的描述,操作系統通過這個描述來實現對程序的運行調度:

在這里插入圖片描述

回到前面提出的問題:

  • CPU通過PCB中的內存指針來找到程序在內存中的地址
  • 通過上下文數據來記錄運行中程序的各種信息
  • 通過程序計數器來找到這個程序即將執行的下一條指令的地址

子進程

我們可以通過 fork 在一個 已經創建的進程內 創建一個 新的進程 ,這個 新的進程 就是 原先進程的 子進程

在子進程創建的時候,它從父進程的PCB中復制了很多數據,如內存指針、上下文數據、程序計數器等,所以它的代碼、數據以及運行的位置,都與父進程一模一樣。

由于代碼段是只讀的,所以兩者的代碼都一樣,不可修改,而兩者雖然虛擬地址相同,但物理地址不同,所以兩者的數據都各自獨立。

總結一下就是:父子進程代碼共享,數據各自開辟空間。 (利用寫時拷貝技術)

Linux 中,我們可以通過 fork 函數 來創建子進程

pid_t fork(void)

我們創建子進程,是希望它和父進程執行不一樣的操作,那么我們該怎么實現呢?

最簡單的方法就是通過 fork 的返回值來進行代碼分流,父進程的返回值是子進程的 pid ,而子進程的返回值是 0 ,通過對返回值的判斷,即可完成代碼的分流。

但是這種方法的代碼十分冗余,還有一種更加優秀的方法——程序替換。


進程狀態

進程有三種基本狀態:
在這里插入圖片描述

  • 執行狀態(running):
    1. 進程正在 CPU上執行;
    2. 只能有一個進程處于執行狀態(單CPU);
  • 就緒狀態(ready):
    1. 進程已獲得除 CPU 外的所有資源,等待分配 CPU 就可執行;
    2. 可以有多個進程處于就緒狀態,組成就緒隊列。
  • 阻塞狀態(waiting):
    1. 進程因自身原因(如:等待I/O資源)而暫停執行,也稱 “等待狀態” 或 “睡眠狀態” 。
    2. 可以有多個進程處于阻塞狀態,組成阻塞隊列

但是在 Linux 中,將狀態細分到了六種:

  • R運行狀態(running): 并不意味著進程一定在運行中,它表明進程要么是在運行中要么在運行隊列里。
  • S睡眠狀態(sleeping): 意味著進程在等待事件完成(這里的睡眠有時候也叫做可中斷睡眠(interruptible sleep)。
  • **D磁盤休眠狀態(Disk sleep):**有時候也叫不可中斷睡眠狀(uninterruptible sleep),在這個狀態的進程通常會等待 IO 的結束。
  • T停止狀態(stopped): 可以通過發送 SIGSTOP 信號給進程來停(T)進程。這個被暫停的進程可以通過發送 SIGCONT 信號讓進程繼續運行。
  • X死亡狀態(dead): 這個狀態只是一個返回狀態,你不會在任務列表里看到這個狀態
  • Z僵死狀態(Zombies): 進程已經退出了但是資源還沒有完全被釋放的一種狀態。

僵尸進程

當子進程退出的時候,如果父進程沒有讀取到子進程的返回值,這時子進程就進入了 僵死狀態

這時就處于一個很尷尬的局面,子進程實際上已經退出了,但是父進程認為它還在執行,所以并沒有釋放它的資源,所以子進程會一直卡在進程表中,等待父進程讀取退出狀態代碼。此時的 子進程 就被稱為 僵尸進程 ,它持有的資源一直無法釋放,也無法再將其殺死。

對于僵尸進程,即使是 kill -9 對其也沒有作用。這時只有兩種解決方法:

  1. 進程等待
  2. 退出父進程

父進程退出,子進程保存退出的狀態就沒有任何意義了,因此就被釋放了。 但是這并不是一個合理的方式,如果為了解決僵尸進程而刻意退出還不應該退出的父進程,不是很好的解決方法,我們應該避免僵尸進程的產生。

從上面可以看出,僵尸進程是非常危險的,因為我們無法通過正常途徑將其解決,同時它會一直占用著我們的資源,同時 PCB 還需要對它的狀態進行維護。并且一個用戶所能創建的進程數量是有限的,如果一個父進程創建了大量的子進程而不進行回收,當達到上限時,我們就無法創建新的程序。


孤兒進程

如果父進程先于子進程退出,那么沒有父進程的子進程會怎么樣呢?持有資源不被回收?就像僵尸進程一樣一直占用資源?

實際上,失去了父進程后的子進程被稱為 “孤兒進程” ,但并不是沒有父進程,而是會被 1 號進程 init 統一收養,然后由 Init 進程回收。


守護進程(精靈進程)

守護進程:一種特殊的孤兒進程,父進程是一號進程,運行在后臺,與終端和登陸會話脫離關系,不受影響。

守護進程通常是一種運行在系統后臺的批處理程序,默默的做一些循環往復的事情。

在這里插入圖片描述


進程地址空間

引言

我們利用一個全局變量val,看看修改子進程中的變量val,父進程會不會發生變化,他們的地址又是否相同:
在這里插入圖片描述
因為子進程運行的位置和父進程一樣,所以先讓父進程睡眠一會,讓子進程先修改。

在這里插入圖片描述

奇怪的事情發生了,明明子進程已經修改了 val ,但是父進程的卻沒變,同時明明父子進程中全局變量 val 的大小都不一樣,但是他們的地址確還是一樣的,這就有些不符合邏輯了,因為一個地址中不可能有兩個同名的變量。

這里就讓我們確定了一件事情,我們在代碼中所看到的地址,并不是真正的地址,而是虛擬內存地址。


頁表

操作系統再引入虛擬地址空間的時候還引入了一種東西,叫做 頁表

通過頁表來映射虛擬地址和物理地址的關系,不同的進程有不同的頁表。上面例子中訪問的 val 地址就是 val 在頁表的編號,在頁表中查找該編號對應的物理內存從而訪問 val 數據。

在這里插入圖片描述

  • 通過在虛擬地址來使數據進行連續的存儲,然后再通過頁表映射到物理內存上,來實現離散式的存儲,提高了內存的利用率。
  • 同時頁表可以針對某個地址設置訪問權限,讓某個地址設置為只讀,通過這種方法來實現內存的訪問控制。
  • 為了能夠使進程具有獨立性,彼此之間不會相互干預,每一個進程都會有它自己的頁表和虛擬地址空間。

現在我們探討幾個問題:

為什么父子進程的代碼相同,且無法修改?

  • 因為通過頁表將代碼段的權限設置為只讀,所以無法修改。

為什么父子進程數據各自開辟空間?

  • 其實父子進程一開始物理地址和虛擬地址都是相同的,但是當任意一個進程中數據發生變化的時候,這個時候操作系統會找到另外一塊物理空間,將數據全部拷貝過去給發生修改的進程使用,并且修改原來的物理空間的權限,使原來的物理空間給另一個進程使用。

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

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

相關文章

Linux 進程控制 :進程創建,進程終止,進程等待,程序替換

文章目錄進程創建進程等待程序替換進程終止進程創建 fork函數: 操作系統提供的創建新進程的方法,父進程通過調用 fork函數 創建一個子進程,父子進程代碼共享,數據獨有。 當調用 fork函數 時,通過 寫時拷貝技術 來拷貝…

Linux 內存管理 | 連續分配方式 和 離散分配方式

文章目錄前言連續分配單一連續分配分區式分配固定分區分配動態分區分配可重定位分區分配離散分配分段分頁多級頁表快表(TLB)段頁式Linux前言 Linux 內存管理 | 虛擬內存管理:虛擬內存空間、虛擬內存分配 Linux 內存管理 | 物理內存、內存碎片、伙伴系統、SLAB分配器…

操作系統 | 用戶態和內核態的切換(中斷、系統調用與過程(庫函數)調用)

文章目錄中斷過程調用系統調用過程調用和系統調用的區別中斷 用戶態、內核態之間的切換是怎么實現的? 用戶態→內核態 是通過中斷實現的。并且 中斷是唯一途徑 。核心態→用戶態 的切換是通過執行一個特權指令,將程序狀態字 (PSW) 的標志位設置為 用戶態 。 中斷…

管道實現父子進程的信息傳遞(二)【標準流和其文件描述符、fwrite函數、perror函數】

文章目錄代碼實現標準流 和 標準流文件描述符代碼中用到的函數fwrite()perror()在復習進程間的通信方式時又寫了一遍,和 管道實現父子進程的信息傳遞(一)【fork函數、pipe函數、write/read操作、wait函數】 的區別不是特別大,只是…

JAVA隨機生成文件名:當前年月日時分秒+五位隨機數

代碼如下: package cn.gov.csrc.util;import java.text.SimpleDateFormat; import java.util.Date; import java.util.Random;public class RandomUtil {/*** 生成隨機文件名:當前年月日時分秒五位隨機數* * return*/public static String getRandomFile…

命名管道實現進程的信息傳遞【mkfifo函數、open函數】

文章目錄代碼實現mkfifo函數open函數代碼實現 #include<fcntl.h> // open() #include<sys/wait.h> // wait() #include<sys/types.h> // mkfifo() #include<sys/stat.h> // mkfifo() #include<iostream> #include<unistd.h> // fork()usi…

Linux 進程 | 進程間的通信方式

文章目錄管道匿名管道 pipe命名管道 FIFO共享內存共享內存的使用流程&#xff1a;消息隊列信號量套接字在之前的博客中講過&#xff0c;虛擬空間出現的其中一個目的就是解決 進程沒有獨立性&#xff0c;可能訪問同一塊物理內存 的問題。因為這種獨立性&#xff0c;進程之間無法…

Linux網絡編程 | socket介紹、網絡字節序與主機字節序概念與兩者的轉換、TCP/UDP 連接中常用的 socket 接口

文章目錄套接字socket 地址通用 socket 地址專用 socket 地址網絡字節序與主機字節序地址轉換TCP/UDP 連接中常用的 socket 接口套接字 什么是套接字&#xff1f; 所謂 套接字 (Socket) &#xff0c;就是對網絡中 不同主機 上的應用進程之間進行雙向通信的端點的抽象。 UNIX/L…

網絡協議分析 | 傳輸層 :史上最全UDP、TCP協議詳解,一篇通~

文章目錄UDP概念格式UDP如何實現可靠傳輸基于UDP的應用層知名協議TCP概念格式保證TCP可靠性的八種機制確認應答、延時應答與捎帶應答超時重傳滑動窗口滑動窗口協議后退n協議選擇重傳協議流量控制擁塞控制發送窗口、接收窗口、擁塞窗口快速重傳和快速恢復連接管理機制三次握手連…

JDom,jdom解析xml文件

1.要解析的文件模板如下&#xff1a; <?xml version"1.0" encoding"GBK"?> <crsc> <data><舉報信息反饋><R index"1"><舉報編號>1</舉報編號><狀態>1</狀態><答復意見>填寫…

網絡協議分析 | 應用層:HTTP協議詳解、HTTP代理服務器

文章目錄概念URLHTTP協議的特點HTTP協議版本格式請求報文首行頭部空行正文響應報文首行頭部空行正文Cookie與SessionHTTP代理服務器正向代理服務器反向代理服務器透明代理服務器概念 先了解一下 因特網&#xff08;Internet&#xff09; 與 萬維網&#xff08;World Wide Web&…

MySQL命令(一)| 數據類型、常用命令一覽、庫的操作、表的操作

文章目錄數據類型數值類型字符串類型日期/時間類型常用命令一覽庫的操作顯示當前數據庫創建數據庫使用數據庫刪除數據庫表的操作創建表顯示當前庫中所有表查看表結構刪除表數據類型 mysql 的數據類型主要分為 數值類型、日期/時間類型、字符串類型 三種。 數值類型 數值類型可…

C++ 繼承 | 對象切割、菱形繼承、虛繼承、對象組合

文章目錄繼承繼承的概念繼承方式及權限using改變成員的訪問權限基類與派生類的賦值轉換回避虛函數機制派生類的默認成員函數友元與靜態成員多繼承菱形繼承虛繼承組合繼承 繼承的概念 繼承可以使得子類具有父類的屬性和方法或者重新定義、追加屬性和方法等。 當創建一個類時&…

博弈論 | 博弈論簡談、常見的博弈定律、巴什博弈

文章目錄博弈論什么是博弈論&#xff1f;博弈的前提博弈的要素博弈的分類非合作博弈——有限兩人博弈囚徒困境合作博弈——無限多人博弈囚徒困境常見的博弈定律零和博弈重復博弈智豬博弈斗雞博弈獵鹿博弈蜈蚣博弈酒吧博弈槍手博弈警匪博弈海盜分金巴什博弈博弈論 什么是博弈論…

MySQL命令(二)| 表的增刪查改、聚合函數(復合函數)、聯合查詢

文章目錄新增 (Create)全列插入指定列插入查詢 (Retrieve)全列查詢指定列查詢條件查詢關系元素運算符模糊查詢分頁查詢去重&#xff1a;DISTINCT別名&#xff1a;AS升序 or 降序更新 (Update)刪除 (Delete)分組&#xff08;GROUP BY&#xff09;聯合查詢內連接&#xff08;inne…

Spring3.1+Quertz1.8實現多個計劃任務

1.主要是配置文件&#xff1a;如下&#xff1a;(這里說明一下主要是看紅色部分的配置&#xff0c;其他的可以根據自己的實際情況修改&#xff0c;這里只是個思路。) <?xml version"1.0"?> <beans xmlns"http://www.springframework.org/schema/beans…

MySQL | 數據庫的六種約束、表的關系、三大范式

文章目錄數據庫約束NOT NULL&#xff08;非空約束&#xff09;UNIQUE&#xff08;唯一約束&#xff09;DEFAULT&#xff08;缺省約束&#xff09;PRIMARY KEY&#xff08;主鍵約束&#xff09;AUTO_INCREMENT 自增FOREIGN KEY&#xff08;外鍵約束&#xff09;CHECK&#xff08…

哈希 :哈希沖突、負載因子、哈希函數、哈希表、哈希桶

文章目錄哈希哈希&#xff08;散列&#xff09;函數常見的哈希函數字符串哈希函數哈希沖突閉散列&#xff08;開放地址法&#xff09;開散列&#xff08;鏈地址法/拉鏈法&#xff09;負載因子以及增容對于閉散列對于開散列結構具體實現哈希表&#xff08;閉散列&#xff09;創建…

C++ 泛型編程(一):模板基礎:函數模板、類模板、模板推演成函數的機制、模板實例化、模板匹配規則

文章目錄泛型編程函數模板函數模板實例化隱式實例化顯式實例化函數模板的匹配規則類模板類模板的實例化泛型編程 泛型編程旨在削減重復工作&#xff0c;如&#xff1a; 將一個函數多次重載不如將他寫成泛型。 void Swap(int& left, int& right) {int temp left;lef…

你真的了解靜態變量、常量的存儲位置嗎?

文章目錄引言C對內存的劃分如何落實在Linux上自由存儲區和堆之間的問題棧常量區靜態存儲區靜態局部變量靜態局部變量、靜態全局變量、全局變量的異同macOS系統的測試結果總結引言 在動態內存的博客中&#xff0c;我提到&#xff1a; 在Linux 內存管理的博客中&#xff0c;我提…