Linux进程实践(3) --进程终止与exec函数族
進程的幾種終止方式
(1)正常退出
? ?從main函數(shù)返回[return]
? ?調(diào)用exit
? ?調(diào)用_exit/_Exit
(2)異常退出
? ?調(diào)用abort???產(chǎn)生SIGABOUT信號
? ?由信號終止??Ctrl+C?[SIGINT]
? ?...(并不完全,?如return/pthread_exit等)
測試[exit/_exit]
//嘗試查看該程序的打印輸出 int main() {cout << "In main, pid = " << getpid(); //去掉了endl;//原理:與終端關(guān)聯(lián),stdout為行緩沖,在文件中,為全緩沖;//詳細信息請參考《UNIX環(huán)境高級編程》(第三版)8.5節(jié), P188//exit(0);為C庫函數(shù),詳細解釋如下_exit(0); }
由圖可知,系統(tǒng)調(diào)用_exit直接陷入內(nèi)核,而C語言庫函數(shù)是經(jīng)過一系列的系統(tǒng)清理工作,再調(diào)用Linux內(nèi)核的;
int main() {cout << "In main, pid = " << getpid();fflush(stdout); //增加了刷新緩沖區(qū)工作_exit(0); }小結(jié):exit與_exit區(qū)別
? ?1)_exit是一個系統(tǒng)調(diào)用,exit是一個c庫函數(shù)
? ?2)exit會執(zhí)行清除I/O緩存
? ?3)exit會執(zhí)行調(diào)用終止處理程序 //終止處理程序如下
?
終止處理程序:atexit
#include <stdlib.h> int atexit(void (*function)(void)); //測試 void exitHandler1(void) {cout << "If exit with exit, the function exitHandler will be called1" << endl; } void exitHandler2(void) {cout << "If exit with exit, the function exitHandler will be called2" << endl; }int main() {cout << "In main, pid = " << getpid() << endl;atexit(exitHandler1); //注意,先注冊的后執(zhí)行atexit(exitHandler2);exit(0); }異常終止
int main() {cout << "In main, pid = " << getpid() << endl;atexit(exitHandler1);atexit(exitHandler2);abort();//exit(0); }exec函數(shù)族
exec替換進程印象
? ?在進程的創(chuàng)建上,Unix采用了一個獨特的方法,它將進程創(chuàng)建與加載一個新進程映象分離。這樣的好處是有更多的余地對兩種操作進行管理。
? ?當(dāng)我們創(chuàng)建了一個進程之后,通常將子進程替換成新的進程映象,這可以用exec系列的函數(shù)來進行。當(dāng)然,exec系列的函數(shù)也可以將當(dāng)前進程替換掉。
? ?exec只是用磁盤上的一個新程序替換了當(dāng)前進程的正文段,?數(shù)據(jù)段,?堆段和棧段.
?
函數(shù)族信息
#include <unistd.h> int execve(const char *filename, char *const argv[],char *const envp[]);#include <unistd.h> extern char **environ; 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[]);說明:
? ?execl,execlp,execle(都帶“l(fā)”,?代表list)的參數(shù)個數(shù)是可變的,參數(shù)以必須一個空指針結(jié)束。
? ?execv和execvp的第二個參數(shù)是一個字符串?dāng)?shù)組(“v”代表“vector”,字符串?dāng)?shù)組必須以NULL結(jié)尾),新程序在啟動時會把在argv數(shù)組中給定的參數(shù)傳遞到main。
? ?名字最后一個字母是“p”的函數(shù)會搜索PATH環(huán)境變量去查找新程序的可執(zhí)行文件。如果可執(zhí)行文件不在PATH定義的路徑上,就必須把包括子目錄在內(nèi)的絕對文件名做為一個參數(shù)傳遞給這些函數(shù);
?
/*總結(jié):l代表可變參數(shù)列表,p代表在path環(huán)境變量中搜索file文件。envp代表環(huán)境變量*/
//示例execlp int main() {pid_t pid = fork();if (pid == 0){if (execlp("/bin/pwd", "pwd", NULL) == -1)err_exit("execlp pwd error");}wait(NULL);pid = fork();if (pid == 0){if (execlp("/bin/ls", "ls", "-l", NULL) == -1)err_exit("execlp ls -l error");}wait(NULL);cout << "After execlp" << endl; } //示例execve int main() {char *const args[] ={(char *)"/bin/date",(char *)"+%F",NULL};execve("/bin/date",args,NULL);cout << "After fork..." << endl;return 0; } //示例execle //1:main.cpp int main() {cout << "In main, pid = " << getpid() << endl;char *const environ[] ={"AA=11","BB=22","CC=33",NULL};execle("./hello","./hello",NULL,environ); //當(dāng)environ填為NULL時,則什么都不傳遞cout << "After fork..." << endl;return 0; } extern char **environ; int main() {cout << "In hello, pid = " << getpid() << endl;cout << "environ:" << endl;for (int i = 0; environ[i] != NULL; ++i){cout << "\t" << environ[i] << endl;} } /* In main, pid = 3572 //PID保持不變 In hello, pid = 3572 environ:AA=11BB=22CC=33 *///示例: execve 與 execlp int main() {pid_t pid = fork();if (pid == -1)err_exit("fork error");else if (pid == 0){//示例execvechar *const args[] ={"echoall","myarg1","MY ARG2",NULL};char *const env[] ={"USER=unknown","PATH=/tmp",NULL};execve("./echoall",args,env);}wait(NULL);pid = fork();if (pid == -1)err_exit("fork error");else if (pid == 0){//示例execlpexeclp("./echoall", "echoall", "only one arg", NULL);}wait(NULL);return 0; }//echoall int main(int argc, char *argv[]) {for (int i = 0; i < argc; ++i)printf("argv[%d]: %s\t", i , argv[i]);printf("\n");for (char **ptr = environ; *ptr != NULL; ++ ptr)printf("%s\n", *ptr);exit(0); }
System系統(tǒng)調(diào)用
? system()函數(shù)調(diào)用“/bin/sh?-c?command”執(zhí)行特定的命令,阻塞當(dāng)前進程直到command命令執(zhí)行完畢,system函數(shù)執(zhí)行時,會調(diào)用fork、execve、waitpid等函數(shù)。
原型:
int system(const char *command);返回值:
????如果無法啟動shell運行命令,system將返回127;出現(xiàn)不能執(zhí)行system調(diào)用的其他錯誤時返回-1。如果system能夠順利執(zhí)行,返回那個命令的退出碼。
//示例 int main() {system("ls -la");return 0; }自己動手寫system
int mySystem(const char *command) {if (command == NULL){errno = EAGAIN;return -1;}pid_t pid = fork();if (pid == -1){perror("fork");exit(-1);}else if (pid == 0){execl("/bin/sh","sh","-c",command,NULL);exit(127);}int status;waitpid(pid,&status,0);//wait(&status);return WEXITSTATUS(status); }int main() {mySystem("ls -la");return 0; }總結(jié)
以上是生活随笔為你收集整理的Linux进程实践(3) --进程终止与exec函数族的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不是之所以不是,所以不是
- 下一篇: 思科与华为生成树协议的对接