Linux系統:進程程序替換以及相關exec接口

本節重點

  • 理解進程替換的相關概念與原理
  • 掌握相關程序替換接口
  • 程序替換與進程創建的區別
  • 程序替換的注意事項

一、概念與原理

進程程序替換是操作系統中實現多任務和資源復用的關鍵機制,允許進程在運行時動態加載并執行新程序。

1.1 定義

進程程序替換是指用新程序的代碼、數據和堆棧完全替換當前進程的地址空間(加載新程序到內存、更新頁表映射、初始化虛擬地址空間,并將進程控制塊(PCB)指向新程序),使進程執行新程序的邏輯,而進程ID(PID)保持不變

1.2 與進程創建的區別

  • 進程創建(fork):創建新進程,并分配PID
  • 進程程序替換:不創建新進程,更改原程序的代碼與數據

二、實現方法 exec函數(6+1)

2.1 語言封裝(6)

2.1.1 execl

函數原型:

int execl(const char *pathname, const char *arg, ...);

參數:

pathname:新程序的路徑+文件名

arg:傳遞給新程序的參數

代碼示例:

#include<iostream>
#include<cstdio>
#include<unistd.h>
int main()
{printf("進程替換之前!\n");int ret=execl("/bin/ls","ls","-a","-l",NULL);//進程替換成功后后續代碼不會執行//只有進程替換出錯后才會執行后續代碼,并設置錯誤碼(void)ret;printf("進程替換之后!\n");return 0;
}

運行結果:

2.1.2 execlp

int execlp(const char *file, const char *arg, ...);

?參數解析:

file:新程序的程序名

arg:傳遞給新程序的參數/執行的方法

代碼示例:

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("進程替換之前!:\n");int ret=execlp("ls","ls","-a","-l",NULL);(void)ret;if(ret==-1)printf("execlp fail!\n");printf("進程替換之后!:\n");return 0;
}

運行結果:

2.1.3 execle

int execle(const char *pathname, const char *arg, char *const envp[]);

?參數解析:?

pathname:新程序的路徑+文件名

arg:傳遞給新程序的參數/執行新程序的方法

envp:傳遞給新程序的環境變量表(以NULL結尾)

代碼示例:

code.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("進程替換之前!:\n");char* const env[]={(char* const)"other=12345",(char* const)"n1=45612",(char* const)"n2=56784",(char* const)"n3=12034",(char* const)"n4=yuejianhua",(char* const)"n5=jinzhiqi",NULL,};int ret=execle("./text","text",NULL,env);if(ret==-1)printf("execlp fail!\n");printf("進程替換之后!:\n");return 0;
}

text.cc?

#include<iostream>
#include<cstdio>
#include<unistd.h>int main(int argc,char* argv[],const char* env[])
{//打印環境變量表:int i=0;while(env[i]){std::cout<<env[i]<<std::endl;i++;}i=0;//打印命令行參數列表:while(argv[i]){std::cout<<argv[i]<<std::endl;i++;} return 0;
}

運行結果:

2.1.4 execv

int execv(const char *pathname, char *const argv[]);

?參數解析:?

pathname:新程序的路徑+文件名

argv:傳遞給新程序的命令行參數列表(以NULL結尾)

代碼示例:

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("進程替換之前!:\n");char* const argv[]={(char* const)"ls",(char* const)"-a",(char* const)"-l",NULL,};int ret=execv("/bin/ls",argv);if(ret==-1)printf("execlp fail!\n");printf("進程替換之后!:\n");return 0;
}

運行結果:

2.1.5 execvp

int execvp(const char *file, char *const argv[]);

?參數解析:?

file:新程序的文件名

argv:傳遞給新程序的命令行參數表(以NULL結尾)

代碼示例:

code.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("進程替換之前!:\n");char* const argv[]={(char* const)"yuejianhua",(char* const)"jinzhiqi",NULL,};int ret=execvp("./text",argv);if(ret==-1)printf("execlp fail!\n");printf("進程替換之后!:\n");return 0;
}

text.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main(int argc,char* argv[],char* env[])
{//打印環境變量表:int i=0;//打印命令行參數列表:while(argv[i]){std::cout<<argv[i]<<std::endl;i++;}  return 0;
}

?運行結果:

2.1.6 execvpe

int execvpe(const char *file, char *const argv[],char *const envp[]);

?參數解析:?

file:新程序的函數名

argv:傳遞給新程序的命令行參數列表(以NULL結尾)

envp:傳遞給新程序的環境變量表(以NULL結尾)

code.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main()
{printf("進程替換之前!:\n");char* const argv[]={(char* const)"yuejianhua",(char* const)"jinzhiqi",NULL,};char* const env[]={(char* const)"other=12345",(char* const)"n1=45612",(char* const)"n2=56784",(char* const)"n3=12034",NULL,};int ret=execvpe("./text",argv,env);if(ret==-1)printf("execlp fail!\n");printf("進程替換之后!:\n");return 0;
}

text.cc

#include<iostream>
#include<cstdio>
#include<unistd.h>int main(int argc,char* argv[],char* env[])
{//打印環境變量表:int i=0;while(env[i]){std::cout<<env[i]<<std::endl;i++;} i=0;//打印命令行參數列表:while(argv[i]){std::cout<<argv[i]<<std::endl;i++;}  return 0;
}

運行結果:

2.2 系統調用(1)

2.2.1 execve

int execve(const char *pathname, char *const argv[],char *const envp[]);

參數解析:?

pathname:新程序的路徑+文件名

argv:傳遞給新程序的命令行參數表(以NULL結尾)

envp:傳遞給新程序的環境變量表(以NULL結尾)

代碼示例:

code.cc

#include<cstdio>
#include<iostream>
#include<unistd.h>
int main()
{std::cout<<"這是進程替換之前"<<std::endl;//傳遞自己的命令行參數與環境變量表char* const argv[]={(char* const)"yuejianhua",(char* const)"jinzhiqi",NULL,};char* const env[]={(char* const)"n1=12345",(char* const)"n2=45678",(char* const)"n3=lut",NULL,};int ret=execve("./text",argv,env);//替換成功后續代碼不會執行if(ret<0){std::cout<<"進程替換失敗!"<<std::endl;}std::cout<<"進程替換之后"<<std::endl;return 0;
}

text.cc

#include<cstdio>
#include<iostream>int main(int argc,char* argv[],char* env[])
{int i=0;while(argv[i]){std::cout<<argv[i]<<std::endl;i++;}i=0;while(env[i]){std::cout<<env[i]<<std::endl;i++;}return 0;
}

?運行結果:

2.3 總結?

函數參數傳遞方式環境變量路徑搜索示例調用
execl??可變參數列? ? ? ? ? ? ?表? ? ?繼承?需完整路? ? ? ? ? ? ?徑execl("/bin/ls", "ls", "-l", NULL)
execlp可變參數列表繼承支持?PATHexeclp("ls", "ls", "-l", NULL)
execle可變參數列表顯式傳遞需完整路徑execle("/bin/ls", "ls", "-l", NULL, envp)
execv參數數組繼承需完整路徑char *argv[] = {"ls", "-l", NULL}; execv("/bin/ls", argv);
execvp參數數組繼承支持?PATHexecvp("ls", argv);
execve參數數組顯式傳遞需完整路徑execve("/bin/ls", argv, envp);

?知識點:

進程程序替換所關聯的exec族函數都有一個顯著特征就是exec+參數傳遞的方式,每個字母代表特定的傳參方法,以下是關于這一類型的總結:

  • l (list)? ? ? :表示給新進程傳參需要一個個傳
  • p(PATH):表示索引新進程可以只傳遞文件名,但是要是自己的代碼文件必須指明路徑
  • v(vector):表示給新進程傳參可以直接使用自定義命令行參數列表
  • e(env)? ? :表示可以給新進程傳遞自定義環境變量表

這里需要注意的是命令行參數列表與環境變量表必須都以NULL結尾。?

exec族函數在底層都封裝了系統調用execve。

當在進程替換的時候顯式地給新進程傳遞環境變量表時傳遞的環境變量表會覆蓋默認的環境變量表,可以參考execle的代碼演示。

三、進程替換的用途

在后期我們可以通過fork+exec機制創建子進程利用進程替換機制使子進程執行定義好的代碼文件。

如:Shell執行命令(簡易版):

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>int main() {pid_t pid = fork();if (pid == 0) {// 子進程:替換為 ls 命令char *argv[] = {"ls", "-l", NULL};execvp("ls", argv); // 自動搜索 PATHperror("execvp failed");exit(1);} else if (pid > 0) {// 父進程:等待子進程結束wait(NULL);printf("Command executed.\n");} else {perror("fork failed");}return 0;
}

fork+exec機制使用后要注意資源回收的問題,使用進程等待的方式回收或使用信signal(SIGCHLD, SIG_IGN)?自動回收(需謹慎)。

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

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

相關文章

從此,K8S入門0門檻!

前言 當你想要入門K8S的時候&#xff0c;往往會被各種概念搞的暈乎乎的&#xff0c;什么API Server&#xff0c;Scheduler&#xff0c;Controller manager&#xff0c;Etcd&#xff0c;Pod&#xff0c;Kubelet&#xff0c;kube-proxy&#xff0c;deployment…… 哪怕你使用了…

[Python開發] 如何用 VSCode 編寫和管理 Python 項目(從 PyCharm 轉向)

在 Python 開發領域,PyCharm 一直是廣受歡迎的 IDE,但其遠程開發功能(如遠程 SSH 調試)僅在付費版中提供。為了適應服務器部署需求,很多開發者開始將目光轉向更加輕量、靈活且免費擴展能力強的 VSCode。本篇文章將詳細介紹,從 PyCharm 轉向 VSCode 后,如何高效搭建和管理…

處方流轉平臺權限控制模塊設計(基于RBAC模型)

這是基于筆者的一些經驗設計并加以完善的方案&#xff0c;僅供參考。 處方流轉平臺權限控制模塊設計&#xff08;基于RBAC模型&#xff09; 1. 需求分析 處方流轉平臺需要嚴格的權限控制&#xff0c;確保&#xff1a; 患者隱私數據保護處方開具、審核、調配、發藥等流程的合…

基于BM1684X+RK3588的智能工業視覺邊緣計算盒子解決方案

智能工業視覺邊緣計算終端技術方案書? ?1. 產品概述? 1.1 產品定位 面向工業自動化場景的高性能AI視覺處理設備集成BM1684X&#xff08;8TOPS INT8&#xff09;AI加速芯片 RK3588&#xff08;6TOPS NPU&#xff09;異構計算支持工業級多相機接入、實時缺陷檢測、高精度定…

軟件工程中的 QFD

: 軟件工程中的 QFD 在軟件工程領域,隨著市場競爭的加劇和用戶需求的日益復雜,如何有效地將用戶需求轉化為軟件產品,成為軟件開發團隊面臨的重要挑戰。而質量功能部署(Quality Function Deployment,QFD)作為一種強大的工具,為這一問題提供了有效的解決方案。 一、QF…

Vue2基礎速成

一、準備工作 首先下載vue2的JavaScript庫&#xff0c;并且命名為vue.min.js 下載鏈接&#xff1a;https://cdn.jsdelivr.net/npm/vue2&#xff08;若鏈接失效可去vue官網尋找&#xff09; CTRLS即可下載保存 文件目錄結構 二、使用操作原生DOM與使用VUE操作DOM的便捷性比較…

日語學習-日語知識點小記-構建基礎-JLPT-N4階段(14):かもしれません (~た?~ない)ほうがいいです

日語學習-日語知識點小記-構建基礎-JLPT-N4階段&#xff08;1&#xff14;&#xff09;&#xff1a;かもしれません &&#xff08;&#xff5e;た?&#xff5e;ない&#xff09;ほうがいいです 1、前言&#xff08;1&#xff09;情況說明&#xff08;2&#xff09;工程師…

傳統銀行服務和 區塊鏈支付無縫融合的一種解決方案

Dragonfly Capital 的合伙人 Alex Pack 曾表示:“DeFi 的目標是重構全球銀行體系,并打造開放且無須許可的經營環境。”在 DeFi 的金融世界中,加密資產架構在區塊鏈上,通過各個協議實現資產之間的高效轉移和價值的實時流通,如 Metamask 錢包的自托管,Uniswap 的資產交易,…

基于深度學習的毒蘑菇檢測

文章目錄 任務介紹數據概覽數據處理數據讀取與拼接字符數據轉化標簽數據映射數據集劃分數據標準化 模型構建與訓練模型構建數據批處理模型訓練 文件提交結果附錄 任務介紹 本次任務為毒蘑菇的二元分類&#xff0c;任務本身并不復雜&#xff0c;適合初學者&#xff0c;主要亮點…

時間給了我們什么?

時間給了我們什么&#xff1f; ?春秋易逝&#xff0c;青春難留&#xff0c;轉瞬之間已過半百。 ?過往中&#xff0c;有得有失&#xff0c;這就是人生。 ?一日三餐四季&#xff0c;日起日落里&#xff0c;成就了昨天、今天和明天&#xff0c;在歷史長河中&#xff0c;皆是…

軟件工程國考

軟件工程-同等學力計算機綜合真題及答案 &#xff08;2004-2014、2017-2024&#xff09; 2004 年軟工 第三部分 軟件工程 &#xff08;共 30 分&#xff09; 一、單項選擇題&#xff08;每小題 1 分&#xff0c;共 5 分&#xff09; 軟件可用性是指&#xff08; &#xff09…

數據結構*棧

棧 什么是棧 這里的棧與我們之前常說的棧是不同的。之前我們說的棧是內存棧&#xff0c;它是JVM內存的一部分&#xff0c;用于存儲局部變量、方法調用信息等。每個線程都有自己獨立的棧空間&#xff0c;當線程啟動時&#xff0c;棧就會被創建&#xff1b;線程結束&#xff0c…

IntelliJ IDEA 保姆級使用教程

文章目錄 一、創建項目二、創建模塊三、創建包四、創建類五、編寫代碼六、運行代碼注意 七、IDEA 常見設置1、主題2、字體3、背景色 八、IDEA 常用快捷鍵九、IDEA 常見操作9.1、類操作9.1.1、刪除類文件9.1.2、修改類名稱注意 9.2、模塊操作9.2.1、修改模塊名快速查看 9.2.2、導…

HTTP 快速解析

一、HTTP請求結構 HTTP請求和響應報文由以下部分組成&#xff08;以請求報文為例&#xff09;&#xff1a; 請求報文結構&#xff1a; 請求行&#xff1a;包含HTTP方法&#xff08;如GET/POST&#xff09;、請求URL和協議版本&#xff08;如HTTP/1.1&#xff0c;HTTP/2.0&…

【AI學習】李宏毅新課《DeepSeek-R1 這類大語言模型是如何進行「深度思考」(Reasoning)的?》的部分紀要

針對推理模型&#xff0c;主要講了四種方法&#xff0c;兩種不需要訓練模型&#xff0c;兩種需要。 對于reason和inference&#xff0c;這兩個詞有不同的含義&#xff01; 推理時計算不是新鮮事&#xff0c;AlphaGo就是如此。 這張圖片說明了將訓練和推理時計算綜合考慮的關系&…

Kotlin Flow流

一 Kotlin Flow 中的 stateIn 和 shareIn 一、簡單比喻理解 想象一個水龍頭&#xff08;數據源&#xff09;和幾個水杯&#xff08;數據接收者&#xff09;&#xff1a; 普通 Flow&#xff08;冷流&#xff09;&#xff1a;每個水杯來接水時&#xff0c;都要重新打開水龍頭從…

【嵌入式Linux】基于ARM-Linux的zero2平臺的智慧樓宇管理系統項目

目錄 1. 需求及項目準備&#xff08;此項目對于虛擬機和香橙派的配置基于上一個垃圾分類項目&#xff0c;如初次開發&#xff0c;兩個平臺的環境變量&#xff0c;阿里云接入&#xff0c;攝像頭配置可參考垃圾分類項目&#xff09;1.1 系統框圖1.2 硬件接線1.3 語音模塊配置1.4 …

Linux運維中常用的磁盤監控方式

在Linux運維中&#xff0c;磁盤監控是一項關鍵任務&#xff0c;因為它能幫助我們預防磁盤空間不足或性能問題導致的服務中斷或數據丟失。讓我們來看看有哪些常用的磁盤監控方法吧&#xff01; 1. 查看磁盤使用情況&#xff08;df命令&#xff09; df命令用于顯示文件系統的…

OpenCV第6課 圖像處理之幾何變換(縮放)

1.簡述 圖像幾何變換又稱為圖像空間變換,它將一幅圖像中的坐標位置映射到另一幅圖像中的新坐標位置。幾何變換并不改變圖像的像素值,只是在圖像平面上進行像素的重新安排。 根據OpenCV函數的不同,本節課將映射關系劃分為縮放、翻轉、仿射變換、透視等。 2.縮放 2.1 函數…

(35)VTK C++開發示例 ---將圖片映射到平面2

文章目錄 1. 概述2. CMake鏈接VTK3. main.cpp文件4. 演示效果 更多精彩內容&#x1f449;內容導航 &#x1f448;&#x1f449;VTK開發 &#x1f448; 1. 概述 與上一個示例不同的是&#xff0c;使用vtkImageReader2Factory根據文件擴展名或內容自動創建對應的圖像文件讀取器&a…