目錄
進(jìn)程的程序替換
0.相關(guān)函數(shù)
1.先看現(xiàn)象
?2.解釋原理
3.將代碼改成多進(jìn)程版
?4.使用其它的替換函數(shù),并且認(rèn)識(shí)函數(shù)參數(shù)的含義
5.其它
進(jìn)程的程序替換
0.相關(guān)函數(shù)
?關(guān)于進(jìn)程替換我們需要了解的6個(gè)函數(shù):
函數(shù)解釋:
- 這些函數(shù)如果調(diào)用成功則加載新的程序從啟動(dòng)代碼開(kāi)始執(zhí)行,不再返回。
- 如果調(diào)用出錯(cuò)則返回-1
- 所以exec函數(shù)只有出錯(cuò)的返回值而沒(méi)有成功的返回值
命名理解:
- l(list) : 表示參數(shù)采用列表
- v(vector) : 參數(shù)用數(shù)組
- p(path) : 有p自動(dòng)搜索環(huán)境變量PATH
- e(env) : 表示自己維護(hù)環(huán)境變量
exec調(diào)用舉例如下:
int main() { char* const argv[] = { "ps", "-ef", NULL }; char* const envp[] = { "PATH=/bin:/usr/bin", "TERM=console", NULL }; execl("/bin/ps", "ps", "-ef", NULL); // 帶p的,可以使用環(huán)境變量PATH,無(wú)需寫(xiě)全路徑 execlp("ps", "ps", "-ef", NULL); // 帶e的,需要自己組裝環(huán)境變量 execle("ps", "ps", "-ef", NULL, envp); execv("/bin/ps", argv); // 帶p的,可以使用環(huán)境變量PATH,無(wú)需寫(xiě)全路徑 execvp("ps", argv); // 帶e的,需要自己組裝環(huán)境變量 execve("/bin/ps", argv, envp); exit(0); }
??????
1.先看現(xiàn)象
先來(lái)看一段代碼:
運(yùn)行結(jié)果:我們發(fā)現(xiàn)讓程序使用exec*函數(shù),可以執(zhí)行起來(lái)新的程序
我們還發(fā)現(xiàn),執(zhí)行玩這條語(yǔ)句,后面的語(yǔ)句都不執(zhí)行了
?2.解釋原理
我們都知道,我們的可執(zhí)行程序運(yùn)行起來(lái)就變成了進(jìn)程。
創(chuàng)建進(jìn)程=創(chuàng)建內(nèi)核相關(guān)管理的數(shù)據(jù)結(jié)構(gòu)(task_struct,mm_struct,頁(yè)表)+代碼和數(shù)據(jù)。
????????內(nèi)存管理的數(shù)據(jù),如代碼段、數(shù)據(jù)段和堆棧等,則包含了程序執(zhí)行所需的數(shù)據(jù)和代碼。
????????當(dāng)我們談?wù)?span style="color:#fe2c24;">進(jìn)程替換時(shí),實(shí)際上是指用一個(gè)新的程序來(lái)完全替代當(dāng)前進(jìn)程的內(nèi)存映像,也就是替換掉原有的代碼段、數(shù)據(jù)段和堆棧等內(nèi)存管理的數(shù)據(jù)。而CPU執(zhí)行的上下文,如程序計(jì)數(shù)器、寄存器和程序狀態(tài)字等,則會(huì)被新的程序所繼承。這樣,新的程序就可以從它的入口點(diǎn)開(kāi)始執(zhí)行,就像它是一個(gè)全新的進(jìn)程一樣。(但他不是一個(gè)全新的程序,因?yàn)檫@個(gè)過(guò)程并沒(méi)有創(chuàng)建新的進(jìn)程,只是替換掉了原進(jìn)程的數(shù)據(jù)和代碼,依舊使用原來(lái)進(jìn)task_struct,mm_struct,頁(yè)表) 用老進(jìn)程的殼子執(zhí)行新的代碼和數(shù)據(jù)。(可以理解成被奪舍了)
? ? ? ??exec*函數(shù)族就是用來(lái)實(shí)現(xiàn)這種進(jìn)程替換的系統(tǒng)調(diào)用。這些函數(shù)會(huì)根據(jù)指定的文件名找到可執(zhí)行的文件,并用它來(lái)替換當(dāng)前進(jìn)程的內(nèi)容。換句話說(shuō),它們會(huì)在當(dāng)前進(jìn)程內(nèi)部執(zhí)行一個(gè)全新的可執(zhí)行文件。
?當(dāng)你調(diào)用一個(gè)exec*函數(shù)時(shí),它會(huì)做以下幾件事情:
- 查找并加載新的程序文件到內(nèi)存。
- 清除當(dāng)前進(jìn)程的內(nèi)存映像,包括代碼段、數(shù)據(jù)段和堆棧等。
- 將新的程序的代碼和數(shù)據(jù)加載到當(dāng)前進(jìn)程的內(nèi)存空間中。
- 更新程序計(jì)數(shù)器,使其指向新程序的入口點(diǎn)。
- 開(kāi)始執(zhí)行新程序。???????
????????值得注意的是,exec*函數(shù)執(zhí)行成功就不需要關(guān)心它的返回值了。這是因?yàn)檎{(diào)用進(jìn)程的實(shí)體,包括代碼段、數(shù)據(jù)段和堆棧等,都已被新的內(nèi)容所取代,只留下進(jìn)程ID等一些表面上的信息保持原樣。所以,一旦exec*函數(shù)執(zhí)行成功,當(dāng)前進(jìn)程就已經(jīng)被新的程序所替代,原有的程序已經(jīng)不再存在。(這就是為什么在上面執(zhí)行那段代碼的時(shí)候,程序最后沒(méi)有執(zhí)行printf("test .... end!\n");)
????????總的來(lái)說(shuō),exec*函數(shù)族是Linux環(huán)境下實(shí)現(xiàn)進(jìn)程替換的重要工具。它們通過(guò)替換當(dāng)前進(jìn)程的內(nèi)存映像來(lái)執(zhí)行新的程序,使得我們可以在一個(gè)進(jìn)程中執(zhí)行不同的程序,從而實(shí)現(xiàn)程序的切換和執(zhí)行流程的改變。
?
3.將代碼改成多進(jìn)程版
????????我想進(jìn)行程序替換,但我不想影響我父進(jìn)程本身,這時(shí)候我們就可以把代碼改成多進(jìn)程版本,讓子進(jìn)程去進(jìn)行替換,父進(jìn)程進(jìn)行wait就行了。
代碼示例:
運(yùn)行結(jié)果:
?4.使用其它的替換函數(shù),并且認(rèn)識(shí)函數(shù)參數(shù)的含義
int execl(const char *path, const char *arg, ...);
path?: 我們要執(zhí)行程序,需要帶路徑(怎么找到程序,你得告訴我)(你想執(zhí)行誰(shuí))
list列表:在命令中怎么執(zhí)行,就這么傳參(標(biāo)準(zhǔn)情況)(你想怎么執(zhí)行)
int execv(const char *path, char *const argv[])
path?:和上面的一樣argv:是一個(gè)指針數(shù)組,直接把參數(shù)傳到數(shù)組里
用法:
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
p:用戶可以不傳要執(zhí)行的文件路徑(但是要穿文件名),查找這個(gè)程序,系統(tǒng)會(huì)自動(dòng)在環(huán)境變量PATH中進(jìn)行查找。用法:
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execvpe(const char *path, char *const argv[], char *const envp[]);
這里的e:表示環(huán)境變量(environment)上面的程序替換,我們替換的都是系統(tǒng)命令,可不可以替換我們自己的程序呢?
這是我們?cè)贑語(yǔ)言程序調(diào)用C++程序的方式
我們?cè)贑++程序中寫(xiě)的
編譯c和c++程序運(yùn)行c程序:我們成功的替換了我們自己的程序
接著談環(huán)境變量。接上面代碼:這一次我們將環(huán)境變量給了execvpe函數(shù)
我們?cè)赾++程序中接收了,命令行參數(shù)表和環(huán)境變量表并將它們打印出來(lái)了:
編譯運(yùn)行看一下效果:
結(jié)論:我們平時(shí)自己運(yùn)行的程序,命令行參數(shù)和環(huán)境變量,是父進(jìn)程通過(guò)將自己的環(huán)境變量表和命令行參數(shù)表通過(guò),execvpe函數(shù)傳遞來(lái)的。而我的父進(jìn)程本身就有一批環(huán)境變量??!從bash來(lái)。(我們是可以將bash的環(huán)境變量表直接傳給子進(jìn)程的,就不做演示了)。
5.其它
?????????事實(shí)上,只有execve是真正的系統(tǒng)調(diào)用,其它五個(gè)函數(shù)最終都調(diào)用 execve,所以execve在man手冊(cè) 第2節(jié),其它函數(shù)在man手冊(cè)第3節(jié)。這些函數(shù)之間的關(guān)系如下圖所示。
下圖exec函數(shù)族 一個(gè)完整的例子:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-861872.html
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-861872.html
到了這里,關(guān)于Linux--進(jìn)程控制(2)--進(jìn)程的程序替換(奪舍)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!