day28:零基础学嵌入式之进程2
1.进程的退出
僵尸进程和孤儿进程
僵尸进程:进程执行结束但空间未被回收变成僵尸进程;
孤儿进程:父子进程中,父进程先消亡,子进程就变成孤儿进程,该子进程就向上找结点,它的父进程发生变化;
2.exit void exit(int status)
(1) 库函数,退出状态,终止的进程会通知父进程,自己使如何终止的。如果是正常结束(终止),则由exit传入的参数。如果是异常终止,则有内核通知异常终止原因的状态。任何情况下,负进程都能使用wait,waitpid获得这个状态,以及资源的回收。
- exit(1);(全面回收工作,文件关闭,堆释放,缓冲区的清理)
(2)功能:让进程退出,并刷新缓存区
(3)参数:status:进程退出的状态(正常退出括号内写0,非正常退出(异常终止),传1)
(4)返回值:缺省
EXIT_SUCCESS 0
EXIT_FAILURE 1
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{printf("made in china\n");exit(0);printf("aaaaa\n");return 0;
}
(4)return 当该关键字出现在main函数中时候可以结束进程,如果在其他函数中则表示结束该函数。
- exit -> 刷新缓存区 -> atexit注册的退出函数 -> _exit
3._exit 系统调用:void _exit(int status);
(1)功能:让进程退出,不刷新缓存区
(2)参数:status:进程退出状态
(3)返回值:缺省
mian(int agc,argv)
{
main();
}
回调函数:某个条件满足时,自动触发
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{printf("made in china\n");_exit(1);printf("aaaaa\n");return 0;
}
4.atexit:int atexit(void (*function)(void));
(1)功能:注册进程正常退出前执行的函数(触发条件);括号内的函数指针,只有条件触发才被动调用
(2)参数:function:函数指针:指向void返回值void参数的函数指针;
(3)返回值:成功返回0,失败返回非0;
(4)当程序调用exit或者由main函数执行return时,所有用atexit,注册的退出函数,将会由注册时顺序倒序被调用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *p;
void clean(void)
{printf("was clean:%s\n",p);free(p);
}
int main(int argc, char **argv)
{p = malloc(32);atexit(clean);strcpy(p, "hello");printf("aaaaaaaaaaa");exit(1);return 0;
}
5.进程空间的随机回收:pid_t wait(int *status);
- eg:exit(20);
- wait/waitpid
为什么要回收:pcb块太多,占了很多内核空间,时间久了会崩溃
(1)功能:该函数可以阻塞等待任意子进程退出,并回收该进程的状态。一般用于父进程回收子进程状态;
(2)参数:status 进程退出时候的状态
如果不关心其退出状态一般用NULL表示
如果要回收进程退出状态,则用WEXITSTATUS回收。
(3)返回值:成功 回收的子进程pid,失败 -1;
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
//括号内空指针
int main(int argc, char **argv)
{pid_t pid = fork();if(pid>0){printf("father: pid: %d\n",getpid());pid_t vel =wait(NULL);printf("pid:%d ,vel :%d\n",pid,vel);}else if (0==pid ){int i = 4;while (--i) {printf("child pid:%d\n",getpid());}}else {perror("pid");exit(1);}return 0;
}
//传参的
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>int main(int argc, char **argv)
{pid_t pid = fork();if(pid>0){printf("father: pid: %d\n",getpid());int status;pid_t vel = wait(&status);if(WIFEXITED(status)){printf("the chile terminated normally ,exit value :%d",WEXITSTATUS(status));}else if(WIFSIGNALED(status)){printf("the chile was terminated by sigal ,exit valu:%d",WTERMSIG(status));}printf("pid:%d ,vel :%d\n",pid,vel);}else if (0==pid ){int i = 15;while (--i) {printf("child pid:%d\n",getpid());sleep(1);}}else {perror("pid");exit(20);}return 0;
}
- WIFEXITED(status) 是不是正常结束
- WEXITSTATUS(status) 正常结束后,使用这个宏去那返回值
- WIFSIGNALED(status) 是不是收到了信号而终止的
- WTERMSIG(status)如果是信号终止的,那么是几号信号。
6.指定空间子进程回收pid_t wait(int *status);
1)如果所有的子进程都在运行,在阻塞
2)如果一个子进程终止,正在等待的父进程则获得终止状态,获得子进程的状态后,立刻返回。
3)如果没有子进程,则立即出错退出。
(1)waitpid(-1,status,0)=wait(status);
pid_t waitpid(pid_t pid, int *status, int options);
< -1 回收指定进程组内的任意子进程
-1 回收任意子进程,组内外
0 回收和当前调用waitpid一个组的所有子进程,组内
> 0 回收指定ID的子进程
waitpid (-1,a,0) == wait(a);
status 子进程退出时候的状态,
如果不关注退出状态用NULL;
options 选项:
0 表示回收过程会阻塞等待
WNOHANG 表示非阻塞模式回收资源。(这事儿办不了,先办后面的,这个一般套在循环中)
返回值:成功 返回接收资源的子进程pid,失败 -1,0,
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>int main(int argc, char **argv)
{pid_t pid = fork();if(pid>0){printf("father: pid: %d\n",getpid());int status;while(1){pid_t vel = waitpid(pid,&status,WNOHANG);//阻塞 blockif(vel == pid)//回收成功{if(WIFEXITED(status))//子进程正常结束{printf("the child terminated normally ,exit value :%d\n",WEXITSTATUS(status));}else if(WIFSIGNALED(status))//{printf("the child was terminated by singal ,exit value :%d\n",WTERMSIG(status));} printf("pid:%d ,vel :%d\n",pid,vel);break;}else if(0 == vel){printf("回收失败!\n");}else {printf("错误回收!\n");return 1;}}}else if (0==pid ){int i = 2;while (--i) {printf("child pid:%d\n",getpid());sleep(1);}}else {perror("pid");exit(20);}return 0;
}
- whereis :查看系统上 ***有没有装上
- echo $PATH:显示的系统路径
- env:显示环境变量;
execute
7.exec族
(1)用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。其实有六种以exec开头的函数,常用4种统称exec函数:
(2)execl:int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
#include <stdio.h>
#include <sys/sysmacros.h>
#include <unistd.h>
int main(int argc, char **argv)
{// execl("/bin/ls", "ls","-l","-a","--color=never",NULL);// printf("safagvada");// execl("/usr/bin/firefox", "firefox","www.baidu.com",NULL);// execl("/bin/pwd", "pwd",NULL);return 0;
}
(3)execlp: int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
#include <stdio.h>
#include <sys/sysmacros.h>
#include <unistd.h>
int main(int argc, char **argv)
{// execlp("ls", "ls","-l","-a","--color=auto",NULL);//execlp("cat", "cat","./01fock.c",NULL);// execlp("./app", "./a.out",NULL);char *args[]= {"./a.out",NULL};char *argn[]={"ls","-l","-a","--color=auto",NULL};// execv("./app",args);execvp("./app", args);return 0;
}
(4)execv: int execv(const char *path, char *const argv[]);
#include <stdio.h>
#include <sys/sysmacros.h>
#include <unistd.h>
int main(int argc, char **argv)
{char *args[]= {"./a.out",NULL};char *argn[]={"ls","-l","-a","--color=auto",NULL};execv("./app",args);return 0;
}
(5)execvp: int execvp(const char *file, char *const argv[]);
#include <stdio.h>
#include <sys/sysmacros.h>
#include <unistd.h>
int main(int argc, char **argv)
{char *args[]= {"./a.out",NULL};char *argn[]={"ls","-l","-a","--color=auto",NULL};execvp("./app", args);return 0;
}
8.sysem:int system(const char *command);
(1)system("vim 1.c");
原理:fork+exec
(2)功能:使用该函数可以将shell命令直接在代码中执行。
(3)参数:command要执行的shell命令
(4)返回值:成功 0,失败 -1