Linux进程实践(3) --进程终止与exec函数族
進程的幾種終止方式
(1)正常退出
? ?從main函數返回[return]
? ?調用exit
? ?調用_exit/_Exit
(2)異常退出
? ?調用abort???產生SIGABOUT信號
? ?由信號終止??Ctrl+C?[SIGINT]
? ?...(并不完全,?如return/pthread_exit等)
測試[exit/_exit]
//嘗試查看該程序的打印輸出 int main() {cout << "In main, pid = " << getpid(); //去掉了endl;//原理:與終端關聯,stdout為行緩沖,在文件中,為全緩沖;//詳細信息請參考《UNIX環境高級編程》(第三版)8.5節, P188//exit(0);為C庫函數,詳細解釋如下_exit(0); }
由圖可知,系統調用_exit直接陷入內核,而C語言庫函數是經過一系列的系統清理工作,再調用Linux內核的;
int main() {cout << "In main, pid = " << getpid();fflush(stdout); //增加了刷新緩沖區工作_exit(0); }小結:exit與_exit區別
? ?1)_exit是一個系統調用,exit是一個c庫函數
? ?2)exit會執行清除I/O緩存
? ?3)exit會執行調用終止處理程序 //終止處理程序如下
?
終止處理程序: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); //注意,先注冊的后執行atexit(exitHandler2);exit(0); }異常終止
int main() {cout << "In main, pid = " << getpid() << endl;atexit(exitHandler1);atexit(exitHandler2);abort();//exit(0); }exec函數族
exec替換進程印象
? ?在進程的創建上,Unix采用了一個獨特的方法,它將進程創建與加載一個新進程映象分離。這樣的好處是有更多的余地對兩種操作進行管理。
? ?當我們創建了一個進程之后,通常將子進程替換成新的進程映象,這可以用exec系列的函數來進行。當然,exec系列的函數也可以將當前進程替換掉。
? ?exec只是用磁盤上的一個新程序替換了當前進程的正文段,?數據段,?堆段和棧段.
?
函數族信息
#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”,?代表list)的參數個數是可變的,參數以必須一個空指針結束。
? ?execv和execvp的第二個參數是一個字符串數組(“v”代表“vector”,字符串數組必須以NULL結尾),新程序在啟動時會把在argv數組中給定的參數傳遞到main。
? ?名字最后一個字母是“p”的函數會搜索PATH環境變量去查找新程序的可執行文件。如果可執行文件不在PATH定義的路徑上,就必須把包括子目錄在內的絕對文件名做為一個參數傳遞給這些函數;
?
/*總結:l代表可變參數列表,p代表在path環境變量中搜索file文件。envp代表環境變量*/
//示例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); //當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系統調用
? system()函數調用“/bin/sh?-c?command”執行特定的命令,阻塞當前進程直到command命令執行完畢,system函數執行時,會調用fork、execve、waitpid等函數。
原型:
int system(const char *command);返回值:
????如果無法啟動shell運行命令,system將返回127;出現不能執行system調用的其他錯誤時返回-1。如果system能夠順利執行,返回那個命令的退出碼。
//示例 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; }總結
以上是生活随笔為你收集整理的Linux进程实践(3) --进程终止与exec函数族的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不是之所以不是,所以不是
- 下一篇: Linux文本模式中文乱码