wordpress 整站帶數(shù)據(jù)互動營銷的方式有哪些
文章目錄
- 1.進程替換原理
- 2.進程替換函數(shù)
- 2.1execl函數(shù)
- 2.2execlp函數(shù)
- 2.3execv函數(shù)
- 2.4execvp函數(shù)
- 2.5execle函數(shù)
- 2.6execve函數(shù)
- 2.7跨語言調(diào)用程序
- 3.總結(jié)
1.進程替換原理
一個程序替換的函數(shù):
#include <unistd.h>`
int execl(const char *path, const char *arg, ...);
示例1:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>
int main()
{printf("before: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());sleep(5);execl("/usr/bin/ls","ls","-l","-a",NULL);printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());
}
示例2:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>int main()
{pid_t id=fork();if(id == 0){//childprintf("before: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());sleep(5);execl("/usr/bin/ls","ls","-l","-a",NULL);printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());exit(0);}//fatherpid_t ret=waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret id: %d\n",getpid(),ret);sleep(5);}return 0;
}
代碼運行結(jié)果如下:
從上面的代碼運行結(jié)果,示例1中可以看出父進程使用execl程序替換函數(shù),會直接替換程序的代碼和數(shù)據(jù);示例2中,父進程創(chuàng)建子進程使用execl程序替換函數(shù),要替換子進程的代碼和數(shù)據(jù)的時候,觸發(fā)只讀權(quán)限寫實拷貝,OS會重新開辟空間存放替換新程序的代碼和數(shù)據(jù)!
問題1:在兩個示例中,為什么沒有執(zhí)行以下代碼語句?
printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());
程序替換成功之后,
exec*
后續(xù)的代碼不會被執(zhí)行;替換失敗呢?才可能執(zhí)行后續(xù)代碼。exec*
函數(shù),只有失敗返回值,沒有成功返回值!!
問題2:CPU是如何得知程序的入口地址?
Linux中形成的可執(zhí)行程序,是有格式的,有一個描述信息的表,該表里面就描述了當前可能程序分了哪些段,包括代碼段,數(shù)據(jù)段等,可執(zhí)行(入口)地址就是表頭地址!CPU把可執(zhí)行程序加載進來的時候,首先獲得表頭地址(可執(zhí)行程序地址),便可以執(zhí)行程序!
問題3:程序替換有沒有創(chuàng)建新的進程?
程序替換沒有創(chuàng)建新進程,只是進行進程的程序代碼和數(shù)據(jù)的替換工作!
替換原理總結(jié)
用
fork
創(chuàng)建子進程后執(zhí)行的是和父進程相同的程序(但有可能執(zhí)行不同的代碼分支),子進程往往要調(diào)用一種exec
函數(shù)以執(zhí)行另一個程序。當進程調(diào)用一種exec
函數(shù)時,該進程的用戶空間代碼和數(shù)據(jù)完全被新程序替換,從新程序的啟動例程開始執(zhí)行。調(diào)用exec
并不創(chuàng)建新進程,所以調(diào)用exec
前后該進程的id并未改變。
2.進程替換函數(shù)
其實有六種以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 execve(const char *path, char *const argv[], char *const envp[]);
2.1execl函數(shù)
int execl(const char *path, const char *arg, ...);
execl
替換函數(shù),參數(shù)path
中,/usr/bin/ls
作為路徑傳參,需要找到可執(zhí)行程序的位置;execl
替換函數(shù)以鏈表的方式,把功能選項連接起來,則是要確定如何執(zhí)行可執(zhí)行程序!
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>int main()
{pid_t id=fork();if(id == 0){//childprintf("before: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());sleep(5);//替換函數(shù)execl("/usr/bin/ls","ls","-l","-a",NULL);printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());exit(0);}//fatherpid_t ret=waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret id: %d\n",getpid(),ret);sleep(5);}return 0;
}
代碼運行結(jié)果如下:
使用命令行參數(shù)指令:
#ls -a -l
指令運行結(jié)果:
簡記:execl
替換函數(shù),arg
參數(shù)與命令行參數(shù)傳遞一致,命令行參數(shù)怎么寫,在execl函數(shù)中就怎么傳!只不過空格換逗號,加NULL
。
2.2execlp函數(shù)
int execlp(const char *file, const char *arg, ...);
示例:
int execl(const char *path, const char *arg, ...);
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>int main()
{pid_t id=fork();if(id == 0){//childprintf("before: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());sleep(5);//替換函數(shù)execlp("ls","ls","-l","-a",NULL);printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());exit(0);}//fatherpid_t ret=waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret id: %d\n",getpid(),ret);sleep(5);}return 0;
}
代碼運行結(jié)果如下:
execlp
替換函數(shù),函數(shù)中名中p
指的是環(huán)境變量PATH
,指令的默認路徑,執(zhí)行進程時系統(tǒng)會去默認路徑尋找,執(zhí)行系統(tǒng)提供的指令時不需要帶上地址;參數(shù)file
中,ls
作為文件名傳參,需要在默認路徑下找到對應的可執(zhí)行程序;"ls","-l","-a",NULL
,execl
替換函數(shù)以鏈表的方式,把功能選項連接起來,則是要確定如何執(zhí)行可執(zhí)行程序!
2.3execv函數(shù)
int execv(const char *path, char *const argv[]);
execv
替換函數(shù)名中的v
是指vector
(數(shù)組),把可執(zhí)行程序的執(zhí)行選項功能放在數(shù)組中,在數(shù)組中以NULL
為結(jié)尾!參數(shù)path
,把可執(zhí)行程序的位置作為參數(shù)傳遞;參數(shù)argv
,把自定義選項功能數(shù)組作為參數(shù)傳遞!
示例:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>int main()
{pid_t id=fork();if(id == 0){//childprintf("before: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());sleep(5);//數(shù)組參數(shù)char* const myargv[]={"ls","-a","-l",NULL};//替換函數(shù)execv("/usr/bin/ls",myargv);printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());exit(0);}//fatherpid_t ret=waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret id: %d\n",getpid(),ret);sleep(5);}return 0;
}
代碼運行結(jié)果如下:
2.4execvp函數(shù)
int execvp(const char *file, char *const argv[]);
execvp
替換函數(shù)名中的v
是指vector
(數(shù)組),把可執(zhí)行程序的執(zhí)行選項功能放在數(shù)組中,在數(shù)組中以NULL
為結(jié)尾;函數(shù)中名中p
指的是環(huán)境變量PATH
,執(zhí)行系統(tǒng)程序時不需要帶路徑;參數(shù)file
,把可執(zhí)行程序的位置作為參數(shù)傳遞;參數(shù)argv
,把自定義選項功能數(shù)組作為參數(shù)傳遞!
示例:
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>int main()
{pid_t id=fork();if(id == 0){//childprintf("before: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());sleep(5);//數(shù)組參數(shù)char* const myargv[]={"ls","-a","-l",NULL};//替換函數(shù)execvp("ls",myargv);printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());exit(0);}//fatherpid_t ret=waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret id: %d\n",getpid(),ret);sleep(5);}return 0;
}
代碼運行結(jié)果如下:
2.5execle函數(shù)
int execle(const char *path, const char *arg, ...,char *const envp[]);
execle
替換函數(shù)名是在‘execl’
函數(shù)基礎上,新增加了envp
參數(shù)??梢詡鬟f‘environ’
環(huán)境變量參數(shù),libc
中定義的全局變量environ
指向環(huán)境變量表,environ
沒有包含在任何頭文件中,所以在使用時 要用extern
聲明。因為環(huán)境變量通常具有全局屬性,子進程繼承父進程的環(huán)境變量;也可以自己設置自定義新的環(huán)境變量數(shù)組,傳遞給子進程!
示例1:
//ohtherExe.cpp
#include <iostream>
using namespace std;int main(int argc, char *argv[], char *env[])
{cout << argv[0] << " begin running" << endl;cout << "這是命令行參數(shù): \n";for(int i=0; argv[i]; i++){cout << i << " : " << argv[i] << endl;}cout << "這是環(huán)境變量信息: \n";for(int i = 0; env[i]; i++){cout << i << " : " << env[i] << endl; }cout<<"xxxxxxxxxxxxxxxxx"<<endl; return 0;
}
//mycommand.c
//新增extern char** environ;//替換函數(shù)execle("./otherExe","otherExe","-a","-b","c",NULL,environ);
代碼運行結(jié)果為:
示例2:
//mycommand.c
//新增部分
char *const myenv[] = {"MYVAL=1111","MYPATH=/usr/bin/XXX",NULL
};
//替換函數(shù)為
execle("./otherExe", "otherExe", "-a", "-w", "-v", NULL, myenv);
代碼運行結(jié)果為:
2.6execve函數(shù)
int execve(const char *path, char *const argv[], char *const envp[]);
execve
替換函數(shù)名中的v
是指vector
(數(shù)組),把可執(zhí)行程序的執(zhí)行選項功能放在數(shù)組中,在數(shù)組中以NULL
為結(jié)尾;envp
參數(shù),傳遞環(huán)境變量為參數(shù)。
示例:
char* const myargv[]={"otherExe","-a","-l",NULL};char* const myenv[]={"MYVAL=111111","MYPATH=/usr/bin/xxx",NULL};extern char** environ;
代碼運行的結(jié)果為:
注意:
libc
中定義的全局變量environ
指向環(huán)境變量表,environ
沒有包含在任何頭文件中,所以在使用時要用extern
聲明;我們?nèi)绻虢o子進程傳遞環(huán)境變量,有兩種方式:①新增環(huán)境變量,在父進程中使用putenv
函數(shù)自己設置的環(huán)境變量;②徹底替換(覆蓋)環(huán)境變量,使用帶“e”
選項的exec
函數(shù)(execle/execve
函數(shù)),傳遞自己設置環(huán)境變量數(shù)組;
2.7跨語言調(diào)用程序
在上面的例子中,我們都是使用我們自己寫的mycommand.c
程序調(diào)用系統(tǒng)的程序(指令),那我們是否可以調(diào)用自己所寫的程序呢?答案是當然可以!
示例1:
python代碼
#!/usr/bin/python3print("hello Python!")
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
#include<stdlib.h>int main()
{pid_t id=fork();if(id == 0){//childprintf("before: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());sleep(5);//替換函數(shù)execl("/usr/bin/python3", "python3", "test.py", NULL);printf("after: I am a process: pid: %d , ppid:%d\n",getpid(),getppid());exit(0);}//fatherpid_t ret=waitpid(id,NULL,0);if(ret > 0){printf("wait success, father pid:%d, ret id: %d\n",getpid(),ret);sleep(5);}return 0;
}
代碼運行結(jié)果如下:
為什么我們可以用C語言程序調(diào)用Python可執(zhí)行程序?
無論什么語言的可執(zhí)行程序運行起來之后變成了進程,便可以通過在子進程中使用exec
系列函數(shù)替換達到調(diào)用的效果!
3.總結(jié)
①exec
系列函數(shù)如果調(diào)用成功,則加載新的程序從啟動代碼開始執(zhí)行不再返回。如果調(diào)用出錯則返回-1,所以exec
函數(shù)只有出錯的返回值,而沒有成功的返回值。
②命名理解記憶
l(list) : 表示參數(shù)采用列表
v(vector) : 參數(shù)用數(shù)組
p(path) : 有p自動搜索環(huán)境變量PATH
e(env) : 表示自己維護環(huán)境變量
③只有execve
函數(shù)是真正的系統(tǒng)調(diào)用,其它五個函數(shù)最終都調(diào)用execve
函數(shù),所以execve在man手冊 第2節(jié),其它函數(shù)在man
手冊第3節(jié)。這些函數(shù)之間的關系如下圖所示: