目錄
?編輯
1.進程基本概念與基本操作
1.1 概念
1.2 描述進程-PCB
1.2.1PCB的基本概念
1.2.2 task_ struct
1.2.3 查看進程
2.進程狀態
2.1 Linux內核源碼展示
2.2 進程狀態查看
?編輯
2.3?Z(zombie)-僵?進程
2.4 僵尸進程的危害
2.5 孤兒進程
3.進程優先級
3.1 基本概念
3.2 查看進程
3.3?PRI andNI
3.4?PRI vs NI
3.5?查看進程優先級的命令
3.6 四個重要概念
4.進程切換
5.內核進程O(1)調度隊列
5.1??個CPU擁有?個runqueue
5.2 優先級
5.3 活動隊列
5.4 過期隊列
5.5?active指針和expired指針
6.環境變量
6.1 基本概念
6.2?常見環境變量
6.3查看環境變量方法
6.4?和環境變量相關的命令
6.5?環境變量的組織方式
6.6?通過代碼如何獲取環境變量
6.7?環境變量通常是具有全局屬性的
1.進程基本概念與基本操作
1.1 概念
課本概念:程序的一個執行實例,對應正在運行的程序等。
內核觀點:作為分配系統資源(CPU時間、內存等)的實體。
1.2 描述進程-PCB
1.2.1PCB的基本概念
? 進程信息存儲在進程控制塊(Process Control Block,簡稱PCB)這一數據結構中,它本質上是一個包含進程所有屬性的集合。
? 教材中將其稱為PCB(Process Control Block),在Linux操作系統中,PCB的具體實現是task_struct結構體。
注意:task_struct是進程控制塊(PCB)的一種實現形式
? Linux系統使用task_struct結構體來描述進程
? task_struct是Linux內核的關鍵數據結構,它被加載到內存中并保存進程的所有相關信息
1.2.2 task_ struct
進程信息分類
? 進程標識符(PID):系統內唯一標識進程的編號,用于進程區分和管理
? 運行狀態:記錄進程當前狀態(運行/等待等)、退出狀態碼及終止信號
? 優先級:決定進程調度順序的優先級數值
? 程序計數器(PC):存儲下一條待執行指令的內存地址
? 內存指針:包含指向程序代碼、進程數據以及共享內存區域的指針集合
? 上下文數據:保存進程運行時CPU寄存器的狀態信息
? I/O狀態:記錄進程I/O請求、分配設備及打開文件列表
? 統計信息:累計CPU使用時間、時鐘周期、時間配額等資源使用記錄
1.2.3 查看進程
(1)進程信息可通過 /proc
系統目錄查看。
(2)大多數進程信息也可以通過用戶級工具(如top和ps)獲取。
ps:
注意:
查看特定進程信息時,可將ps與grep命令結合使用。
2.進程狀態
2.1 Linux內核源碼展示
? 要理解正在運行的進程的概念,需要了解進程的不同狀態。在Linux內核中,進程有時也被稱為任務。
以下狀態定義于內核源代碼中:
? 運行狀態(Running):該狀態并不意味著進程一定正在執行,而是表示進程要么正在運行,要么處于運行隊列中等待調度。
? 睡眠狀態(Sleeping):表示進程正在等待某個事件完成(這種睡眠狀態有時也稱為可中斷睡眠(Interruptible Sleep))。
? 磁盤休眠狀態(Disk Sleep):也稱為不可中斷睡眠狀態(Uninterruptible Sleep),處于該狀態的進程通常正在等待I/O操作完成。
? 停止狀態(Stopped):可以通過發送SIGSTOP信號使進程進入停止狀態(T)。被暫停的進程可以通過發送SIGCONT信號恢復運行。
? 死亡狀態(Dead):該狀態僅表示進程已終止,不會在任務列表中顯示。
2.2 進程狀態查看
ps aux
/ps axj
命令- a:顯示當前終端的所有進程,包括其他用戶的進程
- x:顯示沒有控制終端的進程,例如后臺運行的守護進程
- j:顯示進程所屬的進程組ID、會話ID、父進程ID,以及與作業控制相關的信息
- u:以用戶為中心的格式顯示進程信息,包括用戶、CPU和內存使用情況等詳細信息
2.3?Z(zombie)-僵?進程
- **僵尸狀態(Zombies)**是進程的一種特殊狀態
- 當子進程終止后,若其父進程未通過
wait()
系統調用讀取子進程的退出狀態碼,則該子進程會轉變為僵尸進程 - 僵尸進程會保留在進程表中并維持終止狀態,持續等待父進程獲取其退出狀態信息
- 只要滿足以下條件,子進程就會進入Z狀態:
- 子進程已終止
- 父進程仍在運行
- 父進程未獲取子進程的終止狀態
2.4 僵尸進程的危害
? 進程退出狀態必須被保留,因為它需要向關注它的進程(父進程)匯報任務執行情況。如果父進程遲遲不讀取狀態,子進程就會一直保持Z狀態。
? 保存退出狀態需要用數據記錄,這屬于進程的基本信息,因此存儲在task_struct(PCB)中。這意味著只要Z狀態持續存在,PCB就必須一直維護這些信息。
? 如果一個父進程創建大量子進程卻不回收,確實會造成內存資源浪費。因為每個數據結構對象都會占用內存空間,就像C語言中定義的結構體變量需要分配內存一樣。
? 這確實會導致內存泄漏問題。
2.5 孤兒進程
- 當父進程先退出時,子進程會變成"孤兒進程"
- 孤兒進程將由1號init進程接管
- 最終由init進程負責回收這些孤兒進程
3.進程優先級
3.1 基本概念
- CPU資源分配的順序取決于進程優先級(priority)。優先級高的進程享有優先執行權。在多任務環境下,合理配置進程優先級可以有效提升Linux系統性能。
- 系統還支持將進程綁定到特定CPU運行。通過將非關鍵進程分配到指定CPU,可以顯著優化整體系統性能。
3.2 查看進程
以下信息值得重點關注:
? UID:執行者身份標識
? PID:進程唯一標識符
? PPID:父進程標識符(即衍生該進程的上級進程)
? PRI:進程優先級(數值越小優先級越高)
? NI:進程的nice值
3.3?PRI andNI
? PRI(進程優先級)表示程序被CPU執行的先后順序,數值越小優先級越高
? NI(nice值)是進程優先級的修正數值,用于調整PRI
? 調整后的優先級計算公式為:PRI(new) = PRI(old) + nice
? nice值為負數時,PRI會降低,從而提高進程優先級,使其更快被執行
? 在Linux系統中,調整進程優先級實際上就是修改nice值
? nice值的有效范圍是-20到19,共40個優先級級別
?在Linux操作系統當中,PRI(old)默認為80,即PRI = 80 + NI。
3.4?PRI vs NI
? 需要明確的是,進程的nice值并非進程優先級本身,二者屬于不同概念。但nice值會影響進程優先級的調整。
? 簡單來說,nice值是對進程優先級進行修正的參數。
3.5?查看進程優先級的命令
使用 top 命令調整已運行進程的 nice 值:
- 運行 top 命令
- 在 top 界面按下 r 鍵
- 輸入目標進程的 PID
- 輸入新的 nice 值
注意事項:
- 也可以使用 nice 和 renice 命令來調整優先級
- 相關系統調用函數
3.6 四個重要概念
? 競爭性:系統運行多個進程,但CPU資源有限(可能僅有一個),因此進程間存在資源競爭。為優化資源分配和任務執行效率,引入了優先級機制。
? 獨立性:多進程運行時各自擁有獨立資源,彼此互不干擾。
? 并行:當存在多個CPU時,多個進程可以同時在不同的CPU上運行,實現真正的并行處理。
? 并發:在單個CPU環境下,通過快速切換進程的方式,在特定時間段內讓多個進程交替執行,實現并發效果。
4.進程切換
CPU上下文切換是指任務切換或CPU寄存器切換的過程。當多任務內核需要切換運行任務時,會先保存當前任務的運行狀態(即CPU寄存器中的所有內容),將其存入該任務的堆棧中。隨后,內核會從待運行任務的堆棧中恢復其狀態至CPU寄存器,并開始執行該任務。這一完整的任務切換過程稱為context switch。
5.內核進程O(1)調度隊列
5.1??個CPU擁有?個runqueue
若存在多個CPU,需考慮進程數量的負載均衡問題。
5.2 優先級
? 普通優先級:100~139(對應nice值的常規優先級范圍)
? 實時優先級:0~99(無需關注)
5.3 活動隊列
? 所有未用完時間片的進程按優先級存入該隊列
? nr_active:記錄當前處于運行狀態的進程總數
? queue[140]:每個元素代表一個進程隊列,同優先級進程遵循FIFO調度規則,數組下標直接對應進程優先級
? 進程選擇流程:
- 從下標0開始遍歷queue[140]
- 首個非空隊列即為最高優先級隊列
- 取該隊列首進程運行,完成調度
- 雖然遍歷時間復雜度為O(1),但效率仍不理想
? bitmap[5]:通過5×32位比特位(共140位)標記隊列空狀態,顯著提升非空隊列查找效率
5.4 過期隊列
? 過期隊列與活動隊列具有相同的結構
? 處于過期隊列的進程均為時間片已耗盡的進程
? 一旦活動隊列中的所有進程處理完畢,系統將重新計算過期隊列中進程的時間片
5.5?active指針和expired指針
? active指針始終指向當前活動隊列
? expired指針始終指向過期隊列
? 隨著進程時間片到期,活動隊列中的進程逐漸減少,過期隊列中的進程持續增加
? 這種狀態無需擔心,只需在適當時機交換active和expired指針的內容,就能立即獲得一批新的活動進程
重點:
系統查找合適調度進程的時間復雜度為常量,進程數量的增加不會影響時間成本,這就是著名的O(1)進程調度算法!
6.環境變量
6.1 基本概念
? 環境變量(Environment Variables)是操作系統中用于配置運行環境的關鍵參數
? 以C/C++開發為例:編譯鏈接時無需手動指定庫文件路徑仍能成功生成可執行程序,正是依靠環境變量指引編譯器自動查找所需庫文件
? 環境變量具有兩大典型特征:
- 承載特定的系統功能
- 通常具備全局生效的特性
6.2?常見環境變量
? PATH: 定義系統查找命令的可執行文件路徑
? HOME: 設置用戶的主工作目錄(即用戶登錄Linux系統時的默認目錄)
? SHELL: 指定當前使用的Shell程序,通常為/bin/bash
6.3
查看環境變量方法
To check the value of an environment variable, use:
echo $NAME # Replace NAME with your environment variable
//NAME:你的環境變量名稱
測試PATH
將我們的程序所在路徑加?環境變量PATH當中, 對?測試 export PATH=$PATH:hello 程序所在路徑
直接執行./hello
與執行hello
的區別
為什么某些命令可以直接執行而不需要指定路徑,而我們的二進制程序需要帶上路徑才能運行?
答案:
系統通過PATH
環境變量來查找可執行程序。PATH包含一系列目錄路徑,當輸入命令時,系統會按照以下順序查找:
- 首先檢查是否是內置命令(如cd、echo等shell內置命令)
- 如果不是內置命令,則按PATH變量中列出的目錄順序搜索
- 在找到的第一個匹配的可執行文件處停止
6.4?和環境變量相關的命令
echo
: 顯示指定環境變量的值export
: 設置新的環境變量env
: 顯示所有環境變量unset
: 刪除指定的環境變量set
: 顯示當前 shell 的所有本地變量和環境變量
6.5?環境變量的組織方式
每個程序都會收到?張環境表,環境表是?個字符指針數組,每個指針指向?個以’\0’結尾的環境 字符串
6.6?通過代碼如何獲取環境變量
?
# 命令行第三個參數
借助第三方變量 environ
進行獲取
注意:
libc 中定義的全局變量 environ
指向環境變量表。該變量未被包含在任何頭文件中,因此使用時需要顯式聲明為 extern
。
6.7?環境變量通常是具有全局屬性的
環境變量通常具有全局性特征,可被子進程繼承使用。
直接查看,發現沒有結果,說明該環境變量根本不存在
- 執行
export MYENV="hello world"
設置環境變量 - 重新運行程序后生效,證明環境變量成功傳遞給了子進程
(說明:環境變量具有繼承性,父進程設置的變量會自動傳遞給子進程)