云南建设厅网站安全员报名入口,网站设计行业背景,为wordpress设置标签页,博乐建设工程信息网站前言#xff1a;
程序是指储存在外部存储(如硬盘)的一个可执行文件, 而进程是指处于执行期间的程序, 进程包括 代码段(text section) 和 数据段(data section), 除了代码段和数据段外, 进程一般还包含打开的文件, 要处理的信号和CPU上下文等等.下面让我们开始对Linux进程的学…前言
程序是指储存在外部存储(如硬盘)的一个可执行文件, 而进程是指处于执行期间的程序, 进程包括 代码段(text section) 和 数据段(data section), 除了代码段和数据段外, 进程一般还包含打开的文件, 要处理的信号和CPU上下文等等.下面让我们开始对Linux进程的学习吧
一、exec函数族
将当前进程的.text、.data替换为所要加载的程序的.text、.data然后让进程从新的.text第一条指令开始执行但进程ID不变换核丕换壳。 1.execlp: int execlp(const char *file, const char *arg, ...); 借助 PATH 环境变量找寻待执行程序 参1 程序名 参2 argv0 参3 argv1 ... argvN 哨兵NULL
该函数通常用来调用系统程序。如: ls、date、cp、cat等命令。
#includestdio.h
#includeunistd.h
#includestdlib.hint main(int argc,char *argv[])
{int i;pid_t pid; //创建子进程if(pid -1){perror(fork error);exit(1);}else if(pid 0){ //子进程//execlp(ls,-l,-d,-h,NULL);//错误写法/************************************/execlp(ls,ls,-l,-h,NULL); /************************************/perror(exec error);exit(1);}else if(pid 0){ //父进程sleep(1);printf(Im parent : %d\n,getpid());}return 0;
}date命令的实现
execlp(date,date,NULL); 2.execl: int execl(const char *path, const char *arg, ...); 自己指定待执行程序路径。
#include stdio.hint main(int argc, char **argv)
{printf(Hello, %s!\n, argv[1]);printf(Hello, world!\n);return 0;
}#includestdio.h
#includeunistd.h
#includestdlib.hint main(int argc,char *argv[])
{int i;pid_t pid; //创建子进程if(pid -1){perror(fork error);exit(1);}else if(pid 0){ //子进程//execlp(ls,-l,-d,-h,NULL);//execlp(date,date,NULL);/************************************/execl(./a.out,./a.out,linux,NULL);/************************************/perror(exec error);exit(1);}else if(pid 0){ //父进程sleep(1);printf(Im parent : %d\n,getpid());}return 0;
}3.execvp
加载一个进程使用自定义环境变量env
int execvp(const char*file, const char *argv[]);
#includestdio.h
#includeunistd.h
#includestdlib.hint main(int argc,char *argv[])
{int i;pid_t pid; 创建子进程if(pid -1){perror(fork error);exit(1);}else if(pid 0){ //子进程//execlp(ls,-l,-d,-h,NULL);//execlp(date,date,NULL);//execl(./a.out,./a.out,linux,NULL);/************************************/char *argv[] {date,NULL};execvp(date,argv);/************************************/perror(exec error);exit(1);}else if(pid 0){ //父进程sleep(1);printf(Im parent : %d\n,getpid());}return 0;
}4.exec函数族的一般规律 exec函数一旦调试成功即执行新的程序不返回。只要失败才返回错误值-1。所以通常我们直接在exec函数调用后调用 perror()和exit()。无需if判断。·
二、回收子进程
1.孤儿进程
父进程死亡子进程进孤儿院 孤儿进程:父进程先于子进程结束则子进程成为孤儿进程子进程的父进程成为init进程称为init进程领养孤儿进程。模拟孤儿进程
#include stdio.h
#include unistd.h
#include sys/wait.hint main(void)
{pid_t pid;pid fork();if (pid 0) {while (1) {printf(I am child, my parent pid %d\n, getppid());sleep(1);}} else if (pid 0) {printf(I am parent, my pid is %d\n, getpid());sleep(9);printf(------------parent going to die------------\n);} else {perror(fork);return 1;}return 0;
}查看进程状态ps ajx 进程孤儿院 1 2035 2035 2035 ? -1 Ss 1001 0:00 /lib/systemd/systemd --user解决方法 杀死子进程 kill -9 4871 2 .僵尸进程
子进程死亡父进程一直不管 僵尸进程:进程终止父进程尚未回收子进程残留资源PCB存放于内核中变成僵尸(zombie进程。死亡以后没有回收 特别注意僵尸进程是不能使用kill命令清除掉的。因为kill命令只是用来终止进程的而僵尸进程已经终止。
模拟僵尸进程
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/wait.hint main(void)
{pid_t pid;pid fork();if (pid 0) {printf(---child, my parent %d, going to sleep 10s\n, getppid());sleep(10);printf(-------------child die--------------\n);} else if (pid 0) {while (1) {printf(I am parent, pid %d, myson %d\n, getpid(), pid);sleep(1);}} else {perror(fork);return 1;}return 0;
}查看进程状态ps ajx 解决方法 杀死父进程 kill -9 4770 3.wait
wait函数 回收子进程退出资源 阻塞回收任意一个。 pid_t wait(int *status) 参数传出 回收进程的状态。 返回值成功 回收进程的pid 失败 -1 errno 函数作用1 阻塞等待子进程退出 函数作用2 清理子进程残留在内核的 pcb 资源 函数作用3 通过传出参数得到子进程结束状态 获取子进程正常终止值 WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。 获取导致子进程异常终止信号 WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。
#include stdio.h
#include stdlib.h
#include unistd.h
#include sys/wait.hint main(void)
{pid_t pid, wpid;int status;pid fork();if (pid 0) {printf(---child, my id %d, going to sleep 10s\n, getpid());sleep(10);printf(-------------child die--------------\n);return 73;} else if (pid 0) {//wpid wait(NULL); // 不关心子进程结束原因wpid wait(status); // 如果子进程未终止,父进程阻塞在这个函数上if (wpid -1) {perror(wait error);exit(1);}if (WIFEXITED(status)) { //为真,说明子进程正常终止. printf(child exit with %d\n, WEXITSTATUS(status));}if (WIFSIGNALED(status)) { //为真,说明子进程是被信号终止.printf(child kill with signal %d\n, WTERMSIG(status));}printf(------------parent wait finish: %d\n, wpid);} else {perror(fork);return 1;}return 0;
}正常终止 被信号终止 4.waitpid
waitpid函数 指定某一个进程进行回收。可以设置非阻塞。 waitpid(-1, status, 0) wait(status); pid_t waitpid(pid_t pid, int *status, int options) 参数 pid指定回收某一个子进程pid 0: 待回收的子进程pid -1任意子进程 0同组的子进程。 status传出 回收进程的状态。 optionsWNOHANG 指定回收方式为非阻塞。 返回值 0 : 表成功回收的子进程 pid 0 : 函数调用时 参3 指定了WNOHANG 并且没有子进程结束。 -1: 失败。errno
回收任意子进程
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.h
#include sys/wait.hint main(int argc,char *argv[])
{int i;pid_t pid,wpid;for(i 0;i 5;i){if(fork()0) //循环期间子进程不forkbreak;}if(i 5){ //父进程//wait(NULL);//一次wait/waitpid函数调用只能回收一个子进程/*****************************************/wpid waitpid(-1,NULL,WNOHANG);//回收任意子进程没有结束的子进程父进程直接返回0/****************************************/if(wpid -1){perror(waitpid error);exit(1);}printf(Im parent ,wait a child finish :%d\n,wpid);}else{ //子进程从break跳出sleep(i);printf(Im %dth child\n,i1);}return 0;
}回收指定进程
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.h
#include sys/wait.hint main(int argc,char *argv[])
{int i;pid_t pid,wpid,tmpid;for(i 0;i 5;i){pid fork();if(pid 0){ //循环期间子进程不forkbreak;}if(i 2){tmpid pid;printf(*************pid %d***************\n,pid);}}if(i 5){ //父进程,从表达式2跳出sleep(5); //设置睡眠等所有子进程结束后再回收//wait(NULL); //一次wait/waitpid函数调用只能回收一个子进程//wpid waitpid(-1,NULL,WNOHANG); //回收任意子进程没有结束的子进程父进程直接返回0printf(I am parent , before waitpid , pid %d\n,tmpid);/********将前面sleep(5)屏蔽***************///wpid waitpid(tmpid,NULL,0); //指定一个进程回收阻塞回收/****************************************//*****************************************/wpid waitpid(tmpid,NULL,WNOHANG); //指定一个进程回收不阻塞/****************************************/if(wpid -1){perror(waitpid error);exit(1);}printf(Im parent ,wait a child finish :%d\n,wpid); //wpid回收的是真正的子进程id}else{ //子进程从break跳出sleep(i);printf(Im %dth childpid %d\n,i1,getpid());}return 0;
}5.waitpid回收多个子进程
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.h
#include sys/wait.hint main(int argc,char *argv[])
{int i;pid_t pid,wpid;for(i 0;i 5;i){pid fork();if(pid 0){ //循环期间子进程不forkbreak;}}if(i 5){ //父进程/**********使用阻塞回收子进程********/while((wpid waitpid(-1,NULL,0))){printf(wait child %d\n,wpid);}/***********************************/}else{ //子进程sleep(i);printf(Im %dth child ,pid %d\n,i1,getpid());}return 0;
}结束一个回收一个 之后返回-1表示没有失败了 #include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include pthread.h
#include sys/wait.hint main(int argc,char *argv[])
{int i;pid_t pid,wpid;for(i 0;i 5;i){pid fork();if(pid 0){ //循环期间子进程不forkbreak;}}if(i 5){/*********使用阻塞回收子进程***********//*while((wpid waitpid(-1,NULL,0))){printf(wait child %d\n,wpid);}*//***********************************//*******使用非阻塞方式回收子进程******/while((wpid waitpid(-1,NULL,WNOHANG)) ! -1){if(wpid 0){ printf(wait child %d\n,wpid);}else if(wpid 0){sleep(1);continue;}/************************************/}}else{sleep(i);printf(Im %dth child ,pid %d\n,i1,getpid());}return 0;
}