目錄
一、XTerminal下的Linux系統調用編程
1.1理解進程和線程的概念并在Linux系統下完成相應操作
(1) 進程
(2)線程
(3) 進程 vs 線程
(4)Linux 下的實踐操作
1.2Linux的“虛擬內存管理”和stm32正式物理內存(內存映射)的區別
(1)Linux虛擬內存管理
(2)STM32物理內存映射
(3)主要區別
1.3理解 Linux系統調用函數 fork()、wait()、exec() 等并通過vi 編輯一個c程序
(1)系統調用函數介紹
fork()
wait()
exec()
(2)創建syscall_demo.c
(3)編寫示例程序
(4)編譯運行
二、在樹莓派中創建多個賬號并完成Linux系統調用函數聯系
1.1組員賬號創建
1.2在樹莓派環境中學習并調用fork()、wait()和exec()函數
(1)創建文件 syscall_demo.c
(2)編寫示例程序
(3)編譯運行
一、XTerminal下的Linux系統調用編程
1.1理解進程和線程的概念并在Linux系統下完成相應操作
(1) 進程
定義:進程是程序的一次執行實例,擁有獨立的內存空間、文件描述符和系統資源。
特點:
-
每個進程有唯一的 PID(進程ID)。
-
進程間相互隔離,通信需通過 IPC(進程間通信) 機制(如管道、共享內存等)。
-
創建進程通過
fork()
或exec()
系統調用。
(2)線程
定義:線程是進程內的執行單元,共享同一進程的內存和資源。
特點:
-
線程有獨立的 棧,但共享堆、全局變量和文件描述符。
-
創建線程通過
pthread_create()
(POSIX 線程庫)。 -
輕量級,切換開銷比進程小。
(3) 進程 vs 線程
特性 | 進程 | 線程 |
---|---|---|
獨立性 | 完全隔離 | 共享同一進程資源 |
創建開銷 | 大(需復制內存) | 小(共享內存) |
通信方式 | IPC(管道、信號等) | 直接讀寫共享變量 |
崩潰影響 | 不影響其他進程 | 導致整個進程終止 |
(4)Linux 下的實踐操作
ps -a
通過kill命令嘗試終止該進程
kill -9 PID
我們發現提示沒有那個進程。這是因為該進程為臨時進程,執行完畢后已自動退出,因此報錯 。
我們可以通過下面命令查找系統中所有的進程及其對應的PID
ps -aux
我們可以對應選擇一個進程進行結束
1.2Linux的“虛擬內存管理”和stm32正式物理內存(內存映射)的區別
(1)Linux虛擬內存管理
核心機制: Linux通過虛擬內存抽象物理內存,為每個進程提供獨立的、連續的虛擬地址空間(通常為4GB,32位系統),由MMU(內存管理單元)動態映射到物理內存或磁盤交換空間。
其工作流程為:
進程訪問虛擬地址 → MMU查頁表 → 若頁在物理內存則訪問,否則觸發缺頁異常 → 內核加載缺失頁或終止進程
(2)STM32物理內存映射
核心機制: STM32等嵌入式MCU通常直接操作物理內存,通過內存映射(將外設寄存器、Flash、RAM等硬件資源分配到固定的物理地址。
其典型內存布局為:
0x00000000 - 0x1FFFFFFF: Flash(代碼存儲) 0x20000000 - 0x2001FFFF: SRAM(數據) 0x40000000 - 0x5FFFFFFF: 外設寄存器
(3)主要區別
特性 | Linux虛擬內存 | STM32物理內存映射 |
---|---|---|
地址空間 | 虛擬地址(進程獨立) | 物理地址(全局唯一) |
硬件支持 | 依賴MMU實現地址轉換 | 無MMU,直接訪問物理地址 |
內存擴展 | 支持Swap擴展虛擬內存 | 僅限芯片內置的物理內存 |
內存保護 | 通過頁表實現權限控制 | 無保護,需開發者謹慎操作 |
外設訪問 | 通過/dev/mem 或驅動間接訪問 | 直接讀寫內存映射的外設寄存器 |
使用場景 | 通用計算(多任務、復雜應用) | 實時嵌入式系統(確定性、低延遲) |
存在差異的原因:
Linux需要支持多進程、大內存應用,虛擬內存提供靈活性和安全性。
STM32:追求實時性和確定性,省去MMU降低開銷,適合裸機或RTOS(如FreeRTOS)。
1.3理解 Linux系統調用函數 fork()、wait()、exec() 等并通過vi 編輯一個c程序
(1)系統調用函數介紹
fork()
功能:創建一個新的進程(子進程),子進程是父進程的副本。
返回值:
-
父進程中返回子進程的PID(>0)。
-
子進程中返回0。
-
失敗時返回-1。
頭文件:<unistd.h>
wait()
功能:父進程等待子進程結束,并回收子進程的資源(防止僵尸進程)。
參數:int *status
(存儲子進程的退出狀態)。
返回值:成功時返回子進程PID,失敗時返回-1。
頭文件:<sys/wait.h>
exec()
功能:替換當前進程的映像為新的程序(如運行另一個可執行文件)。
常用變體:
-
execl()
:參數列表形式。 -
execv()
:參數數組形式。 -
execvp()
:自動搜索PATH
環境變量。
返回值:成功時不返回,失敗時返回-1。
頭文件:<unistd.h>
(2)創建syscall_demo.c
vi syscall_demo.c
(3)編寫示例程序
進入vi編譯器后,按"i"進入插入模式
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main() {pid_t pid;int status;pid = fork();if (pid < 0) {fprintf(stderr, "Fork failed!\n");return 1;} else if (pid == 0) {printf("Child Process (PID=%d): Hello from fork()!\n", getpid());execlp("ls", "ls", "-l", NULL);perror("exec failed");return 1;} else {printf("Parent Process (PID=%d): Waiting for child...\n", getpid());wait(&status);printf("Parent: Child exited with status %d\n", WEXITSTATUS(status));}return 0;
}
編寫完成后按Esc退出插入模式,輸入“:wq”保存并退出
注:
保存文件 | Esc → :w → 回車 | 保存但不退出 |
---|---|---|
保存并退出 | Esc → :wq → 回車 | 保存并退出 |
強制退出不保存 | Esc → :q! → 回車 | 丟棄所有修改 |
(4)編譯運行
輸入下面代碼進行編譯運行:
#編譯
gcc syscall_demo.c -o syscall_demo
#添加權限
chmod +x syscall_demo
# 運行
./syscall_demo
結果解釋:
Parent Process (PID=960685): Waiting for child
#父進程(PID=960685)打印信息,表示已通過 fork() 創建子進程,并調用 wait() 進入阻塞狀態,等待子進程結束。Child Process (PID=960686): Hello from fork()!
#子進程(PID=960686)被創建后,打印自己的 PID 和消息,隨后調用execlp("ls", "ls", "-l", NULL)。
子進程的代碼映像被替換為 ls -l 命令,原程序的后續代碼(如 perror)不再執行。-rwxr-xr-x 1 zhangzy group2 17056 Apr 3 23:23 a.out
-rwxr-xr-x 1 zhangzy group2 17056 Apr 3 23:25 syscall_demo
-rw-r--r-- 1 zhangzy group2 610 Apr 3 23:23 syscall_demo.c
-rwxr-xr-x 1 zhangzy group2 65 Apr 3 22:12 test.sh
#ls -l 命令的輸出,顯示當前目錄下的文件詳情:
總用量 48Parent: Child exited with status
#子進程(ls -l)執行完畢后,父進程的 wait(&status) 返回。
WEXITSTATUS(status) 提取子進程的退出狀態碼 0,表示 ls 命令成功執行。
二、在樹莓派中創建多個賬號并完成Linux系統調用函數聯系
1.1組員賬號創建
首先要進行樹莓派的VNC遠程登錄,具體步驟可以看我前面的博客:樹莓派3b:環境配置,VNC遠程控制并進行簡單代碼運行_樹莓派vnc-CSDN博客
先進入VNC命令行
(1)創建用戶
為每個組員創建一個獨立的系統賬號,并生成各自的目錄
sudo adduser user1
sudo adduser user2
(2)配置用戶權限
確保用戶有基本的開發權限,(如sudo權限)
# 將用戶添加到sudo組(允許執行管理員命令)
sudo usermod -aG sudo username1# 驗證用戶組
groups username1
我們通過命令行測試,發現新用戶可以進行登錄(后續代碼也可以通過電腦命令行實現)
1.2在樹莓派環境中學習并調用fork()、wait()和exec()函數
(1)創建文件 syscall_demo.c
nano syscall_demo.c
(2)編寫示例程序
該程序展示了Linux系統調用fork()、exec()、和wait()函數的工作過程
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main() {pid_t pid;int status;// 1. fork() 示例pid = fork();if (pid < 0) {fprintf(stderr, "Fork failed!\n");return 1;} else if (pid == 0) {// 子進程printf("Child Process (PID=%d): Hello from fork()!\n", getpid());// 2. exec() 示例:替換為執行 'ls' 命令execlp("ls", "ls", "-l", NULL);// 如果exec失敗,才會執行到這里perror("exec failed");return 1;} else {// 父進程printf("Parent Process (PID=%d): Waiting for child...\n", getpid());// 3. wait() 示例wait(&status);printf("Parent: Child exited with status %d\n", WEXITSTATUS(status));}return 0;
}
(3)編譯運行
編譯:
gcc syscall_demo.c -o syscall_demo
運行:
./syscall_demo