再談Linux 進程:進程等待、進程替換與環境變量

目錄

1.進程等待

為什么需要進程等待?

相關系統調用:wait()和waitpid()

wait():

waitpid():

解析子進程狀態(status)

2.進程替換

為什么需要進程替換?

相關系統調用:exec函數家族

3.環境變量

?編輯

?編輯


? ? ? ? 本文將對Linux環境下的進程:包括進程創建、終止與進程等待、替換進行講解,作者使用XShell連接配置為CentOs 7.6的主機進行演示,希望能幫助你更好理解操作系統的運行原理!

1.進程等待

????????在操作系統中,進程等待是指父進程主動等待子進程結束執行,并回收子進程資源的過程。這是進程管理中的重要機制,主要用于解決子進程結束后資源釋放和狀態獲取的問題。

為什么需要進程等待?

  1. 回收子進程資源
    ????????子進程結束后,其內核數據結構PCB不會立即釋放,會變成僵尸進程(ps:僵尸進程不能被殺死,只能通過進程等待解決!)父進程通過等待機制回收子進程的殘留資源,避免內存泄漏和系統資源浪費。

  2. 獲取子進程退出狀態
    ? ? ? ? 父進程可以通過等待機制獲取子進程的執行結果(退出的狀態值、被終止收到的信號),進行后續處理。

相關系統調用:wait()和waitpid()

????????先來看看man-pages的wait介紹:

wait():

  • 作用:阻塞當前父進程,直到任意一個子進程結束或被信號中斷。
  • 參數
    status
    是一個指向整數的指針,用于存儲子進程的退出狀態(可通過宏解析)。
  • 返回值
    • 成功時返回結束的子進程的PID;
    • 失敗時返回 -1
//以下是對進程等待的測試
int testwait()
{pid_t id=fork();if(id<0){perror("fork");return 1;}else if(id==0){//childint cnt=5;while(cnt){printf("I am child,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);cnt--;sleep(1);}exit(0);}else {//parentint cnt=10;while(cnt){printf("I am father,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);cnt--;sleep(1);}//這里先不介紹status
-----------------------------------------------------------------------------------------pid_t ret=wait(NULL);//這里wait返回的就是子進程創建成功后返回的pidif(ret==id){printf("success!\n");}
-----------------------------------------------------------------------------------------}return 0; 
}//補充:如果創建了多個子進程,又如何通過wait獲得子進程的運行狀態呢?
//在---畫出的區域可以這樣修改:
//對于多個子進程,只需要將wait遍歷即可for(i=0;i<n;i++){pid_t ret=wait(NULL);if(ret>0){printf("wait %d success\n",ret);}}

waitpid():

  • 作用:等待指定的子進程(更靈活,可設置非阻塞等待)。
  • 參數
  • pid
    • pid =? -1:等待任意子進程;
    • pid > 0:等待 PID 為 pid?的子進程(一般設定為指定等待子進程的PID);
    • status:同上,用于獲取子進程狀態。
    • options
      • 0(默認選擇):阻塞模式,若子進程未結束則一直等待(阻塞狀態)
      • WNOHANG:?非阻塞模式,若子進程未結束則立即返回0
  • 返回值
    • 子進程未結束:根據options返回 0(非阻塞)或阻塞等待;
    • 子進程結束:返回該子進程的 PID;
    • 出錯:返回 -1
int testwaitplus()
{pid_t id=fork();if(id<0){perror("fork");return 1;}else if(id==0){//childint cnt=20;while(cnt){printf("I am child,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);cnt--;sleep(1);}exit(0);}else {//parentint cnt=10;while(cnt){printf("I am father,pid:%d,ppid:%d,cnt:%d\n",getpid(),getppid(),cnt);cnt--;sleep(1);}//pid_t ret=wait(NULL);//這里wait返回的就是子進程創建成功后返回的pidwhile(1){int status=0;// pid_t ret=waitpid(-1,&status,0);pid_t ret=waitpid(-1,&status,WNOHANG);if(ret>0){printf("success!\n");printf("exit successfully,pid:%d\n,exit_code:%d,exit_signal:%d\n",ret,(status>>8)&0xFF,status&0x7F);//還可以用宏if(WIFEXITED(status))//判斷是否異常退出{printf("進程正常退出,無異常!exit_code:%d\n",WEXITSTATUS(status));}exit(0);}else if(ret<0){printf("wait failed\n");}else {printf("子進程還未退出,waiting...\n");}sleep(1);}}return 0; 
}

解析子進程狀態(status)

? ? ? ? 這里的status到底是什么?這里詳細介紹一下這個玩意:

status本質上就是一個整形:4個字節對應32個bit位:

0000 0000 0000 0000 0000 0000 0000 0000

前16位不考慮,后十六位進行寫入標記;
0000 0000 0000 0000

后七位表示異常信號,倒數第八位(標紅)標識core dump,前八位表示退出碼,自己想要查看兩碼可以進行位操作,也可以用宏:
WIFEXITED(status): 若為正常終止子進程返回的狀態,則為真
WEXITSTATUS(status): 若WIFEXITED非零,提取子進程退出碼

其實本質上就是進行的位操作:

(status>>8)&0xFF(0xFF十六進制)

status&0x7F(0x7F十六進制)

2.進程替換

????????在操作系統中,進程替換是指用一個新的程序(可執行文件或腳本)替換當前進程的內存空間、代碼和數據,使進程轉而執行新程序的過程。這一過程不會創建新進程,而是直接覆蓋當前進程的上下文,因此進程的PID保持不變,但執行的內容被完全替換。

為什么需要進程替換?

  1. 執行外部程序
    例如,在Shell中輸入ls命令時,Shel
    l會通過進程替換讓當前子進程執行ls程序。
  2. 程序升級或切換功能
    一個進程在運行中需要切換到另一個功能模塊時,可通過替換自身來實現。

相關系統調用:exec函數家族

? ? ? ?進程替換通過exec系列函數實現,共有 7個函數,統稱為exec函數族。它們的作用是加載并執行一個新程序,替換當前進程的內存空間。

函數原型與區別

上述六個都是庫函數,都是基于系統調用execve實現的:

給出總結:?

函數名參數形式是否搜索?PATH?環境變量能否自定義環境變量
execl可變參數列表(以?NULL?結尾)
execlp可變參數列表是(根據?PATH?查找程序)
execle可變參數列表是(傳入環境變量數組)
execv字符指針數組(argv
execvp字符指針數組
execvpe字符指針數組
execve字符指針數組是(系統調用)

核心區別:

參數傳遞方式:帶?I?的函數(類似鏈表)通過逗號分隔的可變參數列表傳遞參數,最后以NULL結尾;帶?v?的函數(類似數組)通過字符指針數組傳遞參數,類似main函數的參數形式。

是否搜索?PATH:帶?p?的函數會根據系統環境變量PATH查找程序路徑,無需指定絕對路徑。

環境變量控制帶?e?的函數可以自定義環境變量,否則繼承當前進程的環境變量。

底層系統調用execve?是唯一的系統調用,其他函數均是對它的封裝。

exec函數的特點:

執行成功后不返回
? ? ? ? 若?exec?調用成功,當前進程的代碼、數據、堆、棧等會被新程序完全替換,進程從新程序的入口點開始執行,
不會返回原程序。(也沒有辦法返回)僅當?exec?調用失敗時,才會返回?-1,并繼續執行原程序后續代碼。

進程 ID 不變
? ? ? ? 替換前后進程的PID保持不變,因為替換的是進程的 “內容”,而非進程本身。

文件描述符繼承
? ? ? ? 原進程打開的文件描述符在EXEC后默認保持打開狀態。

環境變量繼承
? ? ? ? 原進程所擁有的環境變量在EXEC后默認保持相同。

不是說進程替換是將新的程序所帶有的代碼數據,替換掉原先的代碼數據嗎?PID保持不變,其他全部都被替換掉了,但是!實際上只有內存管理部分大換血,而環境變量,文件描述符包括IO部分完全相同,或者說原封不動地繼承了下去,兩個部分解耦合。

void test1()
{//單個進程進行進程替換printf("this is a begin:pid:%d,ppid:%d\n",getpid(),getppid());execl("/usr/bin/ls","ls","-a","-l",NULL); printf("this is a end:pid:%d,ppid:%d\n",getpid(),getppid());//可以看到進程替換后代碼和數據進行了替換,pid不變,execl后面的代碼不再執行
}extern char** environ;void test2()
{//對exec系統調用函數進行使用char* const arr[]={"ls","-a","-l",NULL };//execlp("testcpp","testcpp",NULL);//execv("/usr/bin/ls",arr);execle("./testcpp","testcpp",NULL,environ);
}

3.環境變量

? ? ? ? 抱歉抱歉,環境變量姍姍來遲,前面已經提到了它,現在來補充認識一下吧:

?????????環境變量是操作系統中存儲的一系列鍵值對,用于控制系統和應用程序的行為。它們在進程的上下文中生效,影響進程的運行環境...

環境變量本質:

存儲形式:以?NAME=VALUE?的格式存儲,例如PATH=/home/usr/testfile。

進程關聯:每個進程啟動時會繼承其父進程的環境變量,并可修改自身的環境變量(但通常不影響父進程)。

存儲位置:進程的環境變量存儲在內存中的環境變量表(由指針environ指向)(使用時記得extern char** environ),可通過main函數的第三個參數envp訪問。

常見環境變量:

變量名作用描述典型值
PATH命令搜索路徑,多個路徑用冒號?:?分隔/usr/local/sbin:/usr/local/bin:...
HOME當前用戶主目錄/home/username
USER當前用戶名username
SHELL用戶默認 Shell 路徑/bin/bash
LANG系統語言和區域設置en_US.UTF-8
PWD當前工作目錄(由 Shell 動態更新)/home/username/projects
TERM終端類型(影響命令行顯示效果,如顏色、光標控制)xterm-256color
EDITOR默認文本編輯器vim?或?nano
JAVA_HOMEJava 運行環境路徑(供 Java 程序查找 JRE/JDK)/usr/lib/jvm/java-17-openjdk
PATH(特殊)注意:部分程序(如?systemd)使用?PATH?以外的變量(如?PATH?需顯式設置)-

?查看環境變量:

set//可以查看所有環境變量,包括本地變量
env//查看環境變量

    查看單個環境變量:

    echo $PATH
    echo $USER
    ....

    設置環境變量:

    臨時設置(僅當前 Shell 會話有效)

    export NAME=VALUE
    export MY_VAR="hello world"  # 聲明為環境變量(可被子進程繼承)
    MY_VAR="hello"  # 僅為當前 Shell 的局部變量(不被子進程繼承)可以用set查到,echo打印
    #因為echo是內建命令,不會將環境變量繼承給子進程#

    ?刪除環境變量:

    unset TEST
    #將TEST環境變量永久刪除#

    環境變量與進程的關系

    1. 繼承性:子進程會自動繼承父進程的環境變量但父進程無法感知子進程對環境變量的修改;進程替換(exec函數族)時,默認繼承當前進程的環境變量,除非經過?execle/execve?顯式傳遞新的環境變量數組。

    2. 作用域:全局變量:通過 export 聲明或寫入系統配置文件,可被所有子進程繼承局部變量:未用 export?聲明的變量,僅在當前 Shell 進程內有效,不被子進程繼承。

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

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

    相關文章

    基于深度學習的無線電調制識別系統

    基于深度學習的無線電調制識別系統 本項目實現了一個基于深度學習的無線電調制識別系統&#xff0c;使用LSTM&#xff08;長短期記憶網絡&#xff09;模型對不同類型的 無線電信號進行自動分類識別。該系統能夠在不同信噪比(SNR)條件下&#xff0c;準確識別多種調制類型&#…

    Python 爬蟲之requests 模塊的應用

    requests 是用 python 語言編寫的一個開源的HTTP庫&#xff0c;可以通過 requests 庫編寫 python 代碼發送網絡請求&#xff0c;其簡單易用&#xff0c;是編寫爬蟲程序時必知必會的一個模塊。 requests 模塊的作用 發送網絡請求&#xff0c;獲取響應數據。 中文文檔&#xf…

    隨機森林(Random Forest)學習

    隨機森林是一種基于集成學習的機器學習算法&#xff0c;屬于Bagging&#xff08;Bootstrap Aggregating&#xff09;方法的一種擴展。它通過組合多個決策樹來提升模型的泛化能力和魯棒性&#xff0c;廣泛用于分類、回歸和特征選擇任務。 1.隨機森林核心思想 1.1少數服從多數 在…

    從 0 到 1!Java 并發編程基礎全解析,零基礎入門必看!

    寫在前面 博主在之前寫了很多關于并發編程深入理解的系列文章&#xff0c;有博友反饋說對博主的文章表示非常有收獲但是對作者文章的某些基礎描述有些模糊&#xff0c;所以博主再根據最能接觸到的基礎&#xff0c;為這類博友進行掃盲&#xff01;當然&#xff0c;后續仍然會接…

    el-input寬度自適應方法總結

    使用 style 或 class 直接設置寬度 可以通過內聯樣式或 CSS 類來直接設置 el-input 的寬度為 100%&#xff0c;使其自適應父容器的寬度 <template><div style"width: 100%;"><el-input style"width: 100%;" v-model"input">…

    解決 Supabase “permission denied for table XXX“ 錯誤

    解決 Supabase “permission denied for table” 錯誤 問題描述 在使用 Supabase 開發應用時&#xff0c;你可能會遇到以下錯誤&#xff1a; [Nest] ERROR [ExceptionsHandler] Object(4) {code: 42501,details: null,hint: null,message: permission denied for table user…

    java每日精進 5.20【MyBatis 聯表分頁查詢】

    1. MyBatis XML 實現分頁查詢 1.1 實現方式 MyBatis XML 是一種傳統的 MyBatis 使用方式&#xff0c;通過在 XML 文件中編寫 SQL 語句&#xff0c;并結合 Mapper 接口和 Service 層實現分頁查詢。分頁需要手動編寫兩條 SQL 語句&#xff1a;一條查詢分頁數據列表&#xff0c;…

    linux taskset 查詢或設置進程綁定CPU

    1、安裝 taskset larkubuntu&#xff1a;~$ sudo apt-get install util-linux larkubuntu&#xff1a;~$ taskset --help 用法&#xff1a; taskset [選項] [mask | cpu-list] [pid|cmd [args...]] 顯示或更改進程的 CPU 關聯性。 選項&#xff1a; -a&#xff0c; --all-tasks…

    Python應用字符串格式化初解

    大家好!在 Python 編程中&#xff0c;字符串格式化是一項基礎且實用的技能。它能讓你更靈活地拼接字符串與變量&#xff0c;使輸出信息更符合需求。本文將為和我一樣的初學者詳細介紹 Python 字符串格式化的常用方法。 定義: 字符串格式化就是將變量或數據插入到字符串中的特定…

    EasyRTC嵌入式音視頻通信SDK一對一音視頻通信,打造遠程辦公/醫療/教育等場景解決方案

    一、方案概述? 數字技術發展促使在線教育、遠程醫療等行業對一對一實時音視頻通信需求激增。傳統方式存在低延遲、高畫質及多場景適配不足等問題&#xff0c;而EasyRTC憑借音視頻處理、高效信令交互與智能網絡適配技術&#xff0c;打造穩定低延遲通信&#xff0c;滿足基礎通信…

    SEO長尾詞優化精準布局

    內容概要 長尾關鍵詞作為SEO策略的核心要素&#xff0c;其價值在于精準捕捉細分需求與低競爭流量入口。相較于短尾詞的高泛化性&#xff0c;長尾詞通過語義擴展與場景化組合&#xff0c;能夠更高效地匹配用戶搜索意圖&#xff0c;降低優化成本的同時提升轉化潛力。本文將從詞庫…

    【MySQL】第7節|Mysql鎖機制與優化實踐以及MVCC底層原理剖析

    鎖等待分析 我們通過檢查InnoDB_row_lock相關的狀態變量來分析系統上的行鎖的爭奪情況 示例場景 假設有兩個用戶同時操作賬戶表 accounts&#xff08;主鍵為 id&#xff09;&#xff1a; 1. 用戶A&#xff1a;執行轉賬&#xff0c;鎖定賬戶 id1 并等待3秒&#xff1a; BEG…

    基于規則引擎與機器學習的智能Web應用防火墻設計與實現

    基于規則引擎與機器學習的智能Web應用防火墻設計與實現 引言&#xff1a;智能防御的必然選擇 在2023年OWASP最新報告中&#xff0c;傳統Web應用防火墻&#xff08;WAF&#xff09;對新型API攻擊的漏報率高達67%&#xff0c;而誤報導致的正常業務攔截損失每年超過2.3億美元。面…

    GIM發布新版本了 (附rust CLI制作brew bottle流程)

    GIM 發布新版本了&#xff01;現在1.3.0版本可用了 可以通過brew upgrade git-intelligence-message升級。 初次安裝需要先執行 brew tap davelet/gim GIM 是一個根據git倉庫內文件變更自動生成git提交消息的命令行工具&#xff0c;參考前文《GIM: 根據代碼變更自動生成git提交…

    PyQt5高效布局指南:QTabWidget與QStackedWidget實戰解析

    &#x1f50d; 問題背景 當界面控件過多時&#xff0c;直接平鋪會導致窗口擁擠、用戶體驗下降。PyQt5提供了兩種高效容器控件&#xff1a; QTabWidget&#xff1a;選項卡式布局&#xff0c;支持直接切換不同功能模塊QStackedWidget&#xff1a;堆棧式布局&#xff0c;需配合導…

    《2.2.1順序表的定義|精講篇》

    上一節學習了線性表的邏輯結構&#xff0c;線性表需要實現哪些基本運算/操作&#xff1f;在本節中&#xff0c;我們將學習順序表的定義、順序表的特性&#xff0c;以及如何用代碼來實現順序表。下個小節我們會介紹基于順序存儲&#xff08;這種存儲結構&#xff09;如何用代碼具…

    【 大模型技術驅動智能網聯汽車革命:關鍵技術解析與未來趨勢】

    大模型技術驅動智能網聯汽車革命&#xff1a;關鍵技術解析與未來趨勢 關鍵詞總結&#xff1a; 大模型技術&#xff1a;LLM、VLM、MLLM、Transformer架構核心場景&#xff1a;智能駕駛、智能座艙、智能網聯關鍵技術&#xff1a;端到端系統、BEVOCC網絡、多模態融合、強化學習挑…

    Rocketmq broker 是主從架構還是集群架構,可以故障自動轉移嗎

    RocketMQ Broker的架構與故障轉移機制 RocketMQ的Broker架構同時采用了主從架構和集群架構&#xff0c;并且支持故障自動轉移。下面詳細說明&#xff1a; 一、架構類型 1. 集群架構 RocketMQ天然支持分布式集群部署 一個RocketMQ集群包含多個Broker組(每組有主從) 不同Bro…

    從零開始建立個人品牌并驗證定位變現性的方法論——基于開源AI大模型、AI智能名片與S2B2C商城生態的實證研究

    摘要&#xff1a;本文提出一種融合開源AI大模型、AI智能名片與S2B2C商城小程序源碼的"最小測試閉環"方法論&#xff0c;通過技術賦能實現個人品牌定位的精準驗證與變現路徑優化。以某美妝領域自由職業者為例&#xff0c;其通過開源AI大模型完成能力圖譜構建與資源匹配…

    SQL進階之旅 Day 2:高效的表設計與規范:從基礎到實戰

    【SQL進階之旅 Day 2】高效的表設計與規范&#xff1a;從基礎到實戰 開篇 在數據庫開發中&#xff0c;一個良好的表設計不僅能夠提高查詢效率&#xff0c;還能避免冗余數據和一致性問題。本文作為"SQL進階之旅"系列的第2天&#xff0c;將重點介紹高效的表設計與規范…