上行10m企業(yè)光纖做網(wǎng)站環(huán)球資源外貿(mào)平臺免費
Linux:Linux:進程終止和進程替換
- 一、進程終止
- 1.1 進程退出場景和創(chuàng)建退出方式
- 1.2 exit 和 _exit區(qū)別
- 二、進程程序替換
- 2.1 進程替換函數(shù)
- 2.2 函數(shù)解釋及命名解釋
- 函數(shù)解釋
- 命名解釋
- 2.3 單進程程序替換(無子進程)
- 2.3.1 帶`l`函數(shù)進程替換(execl為例)
- 2.3.2 帶`p‘函數(shù)進程替換(execlp為例)
- 2.3.3 execv、execvp替換函數(shù)應(yīng)用實例
- 2.4 進程替換其他程序,調(diào)用運行其他語言程序
- 三、進程替換時環(huán)境變量的繼承
- 3.1 進程替換時,子進程環(huán)境變量由來
- 3.2 為何父子進程間環(huán)境變量的繼承不受進程替換的影響
- 3.3 子進程獲取環(huán)境變量的3種方式
一、進程終止
1.1 進程退出場景和創(chuàng)建退出方式
?進程退出有3種場景:代碼執(zhí)行完畢,結(jié)果正確;代碼執(zhí)行完畢,結(jié)果錯誤;代碼異常終止!
?而進程退出的常見方式主要分為以下兩大類:
正常終止 | |
從main返回 | |
調(diào)用exit退出 | |
調(diào)用_exit退出 | |
異常終止 | ctrl c, 信號終止 |
1.2 exit 和 _exit區(qū)別
? exit 和 _exit都可以直接終止進程。但_exit是系統(tǒng)調(diào)用接口,而exit為函數(shù)調(diào)用,底層封裝了exit。
?不同的是,exit終止進程時,會刷新緩沖區(qū),執(zhí)行用戶的清理函數(shù),關(guān)閉流等操作;而_exit則是直接“粗暴”的退出進程,不做任何其他工作!!
二、進程程序替換
?fork()創(chuàng)建子進程時,子進程執(zhí)行的代碼和數(shù)據(jù)都是父進程的一部分。如果我們想讓子進程執(zhí)行全新的代碼,訪問全新的數(shù)據(jù),我們可以采用一種技術(shù) —— 程序替換!而進程替換可以將命令行參數(shù)和環(huán)境變量傳遞給被替換程序的main()函數(shù)參數(shù)!!
2.1 進程替換函數(shù)
?進程替換函數(shù)有6種以exec開頭的函數(shù),統(tǒng)稱為exec函數(shù)。
#include <unistd.h>int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg, ..., char * const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[], char *const envp[]);
?而exec函數(shù)底層都封裝了系統(tǒng)調(diào)用接口execve的瘋轉(zhuǎn),以實現(xiàn)不同的需求!
#include <unistd.h>int execve(const char *filename, char *const argv[], char *const envp[]);
2.2 函數(shù)解釋及命名解釋
函數(shù)解釋
- 如果這些函數(shù)調(diào)用成功,也就意味著進程替換成功。此時重新加載新的程序,從啟動代碼開始執(zhí)行,并且不再返回。即進程替換后,執(zhí)行新程序,執(zhí)行完后直接退出!!
- 如果進程替換函數(shù)執(zhí)行失敗,此時返回值設(shè)為-1。
- exec函數(shù)只有出錯的返回值,沒有成功的返回值。
命名解釋
- l(list):參數(shù)采用列表形式。
- v(vector):參數(shù)采用數(shù)組。
- p(path):帶p表示執(zhí)行程序時,OS會自帶去環(huán)境變量PATH中查找路徑。
- e(env):表示自己維護環(huán)境變量。
2.3 單進程程序替換(無子進程)
2.3.1 帶l
函數(shù)進程替換(execl為例)
?下面我們在一段代碼的開頭和結(jié)尾分別輸出打印相關(guān)信息,然后兩段信息輸出代碼直接調(diào)用execl
替換ls -a-l
。
【源代碼】:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>int main()
{printf("pid: %d, ecec command begin!\n", getpid());//進程替換,執(zhí)行l(wèi)s指令相關(guān)程序execl("/usr/bin/ls", "ls", "-a", "-l", NULL);printf("pid: %d, ecec command end!\n", getpid());return 0;
}
【運行結(jié)果】:
【函數(shù)參數(shù)原型解釋】:
2.3.2 帶`p‘函數(shù)進程替換(execlp為例)
【源代碼】:(頭文件省略)
int main()
{printf("pid: %d, ecec command begin!\n", getpid());execlp("pwd", "pwd", NULL);printf("pid: %d, ecec command end!\n", getpid());return 0;
}
【運行結(jié)果】:
【函數(shù)參數(shù)原型解釋】:
2.3.3 execv、execvp替換函數(shù)應(yīng)用實例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>int main()
{char *const argv[] = {"ls","-l","-a",NULL};printf("pid: %d, ecec command begin!\n", getpid());、// 和execl、execlv類似,只不過下面函數(shù)時通過指針數(shù)組的方式,指明替換程序的執(zhí)行方式!!execv("/usr/bin/ls", argv);execvp("ls", argv);printf("pid: %d, ecec command end!\n", getpid());return 0;
}
2.4 進程替換其他程序,調(diào)用運行其他語言程序
?上述所有的程序替換都是替換系統(tǒng)指令程序,那如何替換自己寫的程序。
?下面我們在c程序中創(chuàng)建子進程,讓子進程發(fā)送進程替換一段c++可執(zhí)行程序,并且父進程等待子進程!!
【待替換C++程序】:
#include <iostream>int main()
{std::cout << "hello c++!" << std::endl;std::cout << "hello c++!" << std::endl;std::cout << "hello c++!" << std::endl;return 0;
}
【主代碼C程序】:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>extern char **environ;int main()
{pid_t id = fork();if(id == 0){printf("pid: %d, ecec command begin!\n", getpid());execl("./mytest", "mytest");//替換C++程序//替換失敗,執(zhí)行下面代碼printf("pid: %d, ecec command end!\n", getpid());exit(1);}pid_t rid = waitpid(-1, NULL, 0);if(rid == id){printf("wait pid: %d success!!!\n", rid);}return 0;
}
【運行結(jié)果】:
- 為啥在c程序中,可以直接替換c++程序?根本原因在于exec函數(shù)發(fā)生的是進程替換,任何語言程序一旦運行起來就變成了進程,便可發(fā)生進程替換。系統(tǒng)大于一切!!
三、進程替換時環(huán)境變量的繼承
3.1 進程替換時,子進程環(huán)境變量由來
?環(huán)境變量是數(shù)據(jù),所有可以通過地址空間實現(xiàn)父子間通過寫時拷貝的方式共享數(shù)據(jù) —— 環(huán)境變量。所以當(dāng)通過exec函數(shù)進行進程替換時,子進程的環(huán)境變量是直接從父進程來的。
3.2 為何父子進程間環(huán)境變量的繼承不受進程替換的影響
?父進程和子進程間通過寫時拷貝的方式,讓環(huán)境變量別子進程繼承,從而實現(xiàn)環(huán)境變量的全局性!但為何調(diào)用exec函數(shù)進行進程替換后,環(huán)境變量沒有發(fā)生修改,變?yōu)楸惶鎿Q程序的環(huán)境變量?
?原因很簡單,程序替換,只替換新程序的代碼和數(shù)據(jù),環(huán)境變量不會被替換!!
3.3 子進程獲取環(huán)境變量的3種方式
- 操作系統(tǒng)直接將環(huán)境變量傳遞給子進程,子進程直接用。或者直接通過
execle、execvpe
的最后一個參數(shù)直接傳遞給子進程!
【實例】:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
extern char **environ;int main()
{pid_t id = fork();if(id == 0){execle("./mytest", "mytest", NULL, environ);//進程替換,直接將environ傳遞給子進程exit(1);}pid_t rid = waitpid(-1, NULL, 0);if(rid == id){printf("wait pid: %d success!!!\n", rid);}return 0;
}
- 直接構(gòu)造自己的環(huán)境變量表傳遞給子進程。
【實例】:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
extern char **environ;int main()
{pid_t id = fork();if(id == 0){execle("./mytest", "mytest", NULL, environ);//進程替換,直接將environ傳遞給子進程exit(1);}pid_t rid = waitpid(-1, NULL, 0);if(rid == id){char *const envp[] = {"MYENV1 = 111111111111111111","MYENV2 = 111111111111111111","MYENV3 = 111111111111111111",NULL};execle("./mytest", "mytest", NULL, envp);//直接將自己構(gòu)造的函數(shù)變量表envp傳遞給子進程}return 0;
}
- 借助putenv(),新增環(huán)境變量給父進程然后傳遞給子進程
【實例】:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>extern char **environ;int main()
{pid_t id = fork();if(id == 0){char *myenv = "MYENV = 111111111111111111";putenv(myenv);//將環(huán)境變量MYENV添加到父進程環(huán)境變量表中execl("./mytest", "mytest");//直接傳遞給子進程exit(1);}pid_t rid = waitpid(-1, NULL, 0);if(rid == id){printf("wait pid: %d success!!!\n", rid);}return 0;
}