目錄
一、Linux的進程、線程概念
(一)命令控制進程
1、命令查看各進程的編號pid
2、命令終止一個進程pid
二、初識Linux系統的虛擬機內存管理
(一)虛擬機內存管理
(二)與STM32內存管理對比
三、Linux調用函數編程
具體操作:
四、總結
一、Linux的進程、線程概念
Linux中的進程(Process)和線程(Thread)是操作系統進行任務調度的核心概念。
- 進程是資源分配的基本單位,每個進程擁有獨立的內存空間、文件描述符等系統資源。進程之間相互隔離,需通過進程間通信(IPC)交換數據。
- 線程是進程內的執行單元,屬于同一進程的多個線程共享進程的內存和資源(如代碼段、全局變量)。線程獨立調度,切換開銷小,適合需要并發執行的場景。
?????????在Linux中,線程通過輕量級進程(Lightweight Process, LWP)實現,底層由clone()
系統調用創建。內核使用task_struct
結構統一管理進程和線程,區別在于資源共享程度:線程屬于同一線程組(TGID相同),共享內存;而不同進程的TGID不同,資源獨立。
(一)命令控制進程
????????如表為部分控制進程二點命令,但是此處我們著重操作查看進程編號和終止進程
分類 | 命令 | 功能描述 |
---|---|---|
查看進程信息 | ps | 列出當前進程快照 |
top / htop | 動態監控進程資源占用 | |
終止進程 | kill | 通過PID發送信息終止進程 |
killall | 通過進程名批量終止 | |
調整優先級 | nice | 啟動新進程時設置優先級(范圍:-20~19) |
renice | 修改已運行進程的優先級 | |
后臺進程管理 | nohup | 忽略掛斷信號,使進程在終端關閉后仍運行 |
jobs/fg/bg | 管理當前終端的后臺作業 |
1、命令查看各進程的編號pid
????????進程編號(PID)是Linux內核為每個運行中的進程分配的唯一數字標識。通過PID,用戶可以精準定位目標進程并對其進行管理。以下命令可用于快速獲取當前系統中的進程信息:
查看進程此處我用的指令是:
ps -a
則會顯示出如下圖所示結果:
2、命令終止一個進程pid
????????當進程出現異常或需要主動釋放資源時,可通過發送終止信號(Signal)強制結束進程。Linux提供多種信號類型,默認使用SIGTERM
(15)請求進程正常退出,若未響應可升級至SIGKILL
(9)強制終止。
????????此處要達到終止一個進程的效果,我們可以先創建一個新的進程,再強制終止,步驟如下:
- 啟動測試進程:
sleep 300 & # 后臺運行一個休眠300秒的進程
- 查找其PID:
ps -a | grep sleep
- 終止進程
kill 1936
二、初識Linux系統的虛擬機內存管理
(一)虛擬機內存管理
????????Linux內存管理通過虛擬內存和分頁技術為進程提供獨立地址空間,由MMU通過頁表映射至物理內存或Swap。采用按需分頁,訪問時觸發缺頁中斷分配內存;內存不足時通過LRU等算法換出非活躍頁,由kswapd回收資源,極端時OOM Killer終止進程。寫時復制優化進程創建效率。該機制確保進程隔離、內存高效利用及動態擴展能力
(二)與STM32內存管理對比
????????Linux的虛擬內存管理與STM32的真實物理內存映射在設計理念和應用場景上有顯著區別,主要體現在以下幾個方面:
-
地址隔離與抽象
Linux通過MMU將虛擬地址映射到物理內存,實現進程間內存隔離;STM32直接操作物理地址,無隔離,需手動管理布局,易因越界操作崩潰。 -
保護與擴展能力
Linux利用頁表權限和Swap擴展內存,防御攻擊;STM32依賴有限MPU保護關鍵區,無動態擴展,內存嚴格受限。 -
實時性與開銷
STM32物理內存訪問確定、無轉換延遲,適合實時控制;Linux可能因頁錯誤或Swap引入延遲,且MMU管理消耗資源。 -
開發模式
Linux自動管理內存,簡化開發;STM32需手動分配內存/外設,底層控制強但易出錯。
三、Linux調用函數編程
????????接下來我們將熟悉通過虛擬機在Linux系統中編寫c語言程序,熟練調用?fork()、wait()、exec() 等函數。首先我們了解一下上述幾個函數的含義:
1、fork( ):創建子進程
-
功能:復制當前進程(父進程),生成一個幾乎完全相同的子進程。
-
特點:
-
調用一次,返回兩次:父進程返回子進程的 PID(進程標識符),子進程返回?
0
。 -
子進程繼承父進程的代碼、數據段、堆棧和文件描述符等資源。
-
2、wait( )?:回收子進程資源
- 功能:父進程阻塞等待子進程終止,并回收其資源
-
特點:
-
wait(NULL) 等待任意子進程結束;waitpid( ) 可指定等待特定子進程。
-
通過參數獲取子進程退出狀態。
-
3、exec( )執行新程序
-
功能:加載并運行一個新的可執行程序,替換當前進程的代碼和數據。
-
特點:
-
屬于函數族,參數傳遞方式不同。
-
調用成功后,原進程的代碼段、數據段等被新程序完全覆蓋,但進程 PID 不變。
-
具體操作:
1、打開XTerminal
登錄我們老師分配的阿里云服務器Ubuntu系統的賬號,進入終端
2、通過命令創建Homework文件夾
mkdir ~/homework && cd ~/homework
3、在homework文件夾中通過vi命令創建C語言文件并寫入測試代碼
vi example.c
測試代碼:
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>int main() {pid_t pid = fork();if (pid == -1) {perror("fork失敗");exit(EXIT_FAILURE);} else if (pid == 0) {// 子進程執行ls -lprintf("子進程PID: %d\n", getpid());execl("/bin/ls", "ls", "-l", NULL);// 若execl失敗,執行以下代碼perror("execl失敗");exit(EXIT_FAILURE);} else {// 父進程等待子進程printf("父進程,等待子進程PID: %d\n", pid);int status;wait(&status);if (WIFEXITED(status)) {printf("子進程退出碼: %d\n", WEXITSTATUS(status));}printf("父進程結束\n");}return 0;
}
代碼分析:
(1)使用 fork( ) 創建子進程
pid_t pid = fork();
- 調用fork( )創建一個新進程(子進程)。
(2)錯誤處理:fork失敗
if (pid == -1) {perror("fork失敗");exit(EXIT_FAILURE);
}
-
如果fork( )?失敗(返回?
-1
),打印錯誤信息并終止程序。
(3)子進程邏輯
else if (pid == 0) {// 子進程代碼printf("子進程PID: %d\n", getpid());execl("/bin/ls", "ls", "-l", NULL);perror("execl失敗");exit(EXIT_FAILURE);
}
- 子進程通過getid( )獲取自身PID并打印,隨后調用execl("/bin/ls","ls","-l",NULL)執行ls -1命令,若路徑或參數錯誤則通過perror( )輸出錯誤信息并調用exit(1)終止自身。
(4)父進程邏輯
else {// 父進程代碼printf("父進程,等待子進程PID: %d\n", pid);int status;wait(&status);if (WIFEXITED(status)) {printf("子進程退出碼: %d\n", WEXITSTATUS(status));}printf("父進程結束\n");
}
- 父進程通過
wait(&status)
阻塞等待子進程終止,檢查其是否正常退出(WIFEXITED
),獲取退出碼(WEXITSTATUS
),最后打印父進程結束信息。
4、對編輯好的文件保存并退出
????????在下方的對話框中輸入如下指令則可進行對應操作
(1)保存文件:
:w
- :表示進入命令輸入狀態。
- w 表示寫入(write),即保存文件。
(2)退出 vi
:q
- q表示退出(quit)。
- 按?ctrl+enter?退出 vi。
5、編譯并運行
????????回到終端界面輸入以下命令即可編譯并運行
gcc example.c -o example
./example
結果:
四、總結
????????在本次學習中,我深入理解了Linux的進程與線程概念,掌握了通過ps、kill等命令查看和終止進程的操作,并通過fork()、wait()、exec()函數實現父子進程協作的編程實踐。對比Linux虛擬內存與STM32物理內存管理機制,我認識到前者通過隔離與動態擴展提升安全性與靈活性,而后者以實時性和確定性服務于嵌入式場景。通過編寫C程序調用系統函數,我進一步熟悉了多進程資源管理及錯誤處理流程,鞏固了理論與實踐的銜接能力,為后續復雜系統開發奠定了基礎。