●进程终止
一、进程退出场景
1.代码运行完毕,结果正确。
2.代码运行完毕,结果不正确。
3.代码异常终止。
二、进程常见退出方法
●正常终止(可以通过 echo $? 查看进程退出码):
1.调用_exit函数
#include <unistd.h>
void _exit(int status);
参数:status 定义了进程的终止状态,父进程通过wait来获取该值
注意:虽然status是int,但是仅有低8位可以被父进程所用。所以_exit(-1)时,在终端执行$?发现返回值是255。
2.调用exit函数
#include <unistd.h>
void exit(int status);
exit最后也会调用exit, 但在调用exit之前,还做了其他工作:
1. 执行用户通过 atexit或on_exit定义的清理函数。
2. 关闭所有打开的流,所有的缓存数据均被写入。
3. 调用_exit。
举例:
int main()
{
printf("hello");
_exit(0);
}
什么也不输出
int main()
{
printf("hello");
exit(0);
}
输出hello
3.调用return
return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当做exit的参数。
●异常退出:
ctrl + c,信号终止
●进程程序替换
一、程序替换的原理
1.用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支)
2.子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替
换,从新程序的启动例程开始执行。
3.调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
4.把即将运行的程序加载到内存中,那么页表映射的代码段就被改了。
5.调用exec成功没有返回值,失败返回-1。
调用exec成功,则当前进程的代码和数据已经被替换,以前的堆和栈已经被销毁,返回值也保存在栈中,栈已经被销毁,则返回值不存在。
二、exec系列替换函数
1.六个替换函数
#include<unistd.h>
int execl(const char* path,const char* arg,...); //后面以NULL结束
int execlp(const char* file,const char* arg,...);
int execle(const char* path,const char* grg,...,char* const envp[]);
int execv(const char* path,const char* argv); //argv数组以NULL结束
int execvp(const char* file,const char* argv);
int execve(const char* path,const char* argv,char* const envp[]); //envp数组以NULL结束
事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve。
2.函数解释
path:表示对应的文件在哪个目录下(要执行的程序是哪一个)
file:只用填文件名,系统会在PATH下找
envp[]:表示自己设置的,替换后的程序的环境变量
l(list):表示参数采用列表形式
v(vector):参数采用数组形式
p(path):有p自动搜索环境变量PATH
e(envp):表示自己设置环境变量(设置的环境变量是什么,则最新程序的环境变量就是什么)
3.使用
1>int execl(const char* path,const char* arg,...)
示例一:
#include<stdio.h>
#include<unistd.h>
int main()
{
execl("/bin/pwd","pwd",NULL);
return 0;
}
功能:让进程执行pwd命令。
示例二:
hello.c
int main()
{
printf("hello\n");
return 0;
}
exec.c
int main()
{
execl("./hello","./hello",NULL);
return 0;
}
功能:让进程执行hello进程
2>int execlp(const char* file,const char* arg,...)
int main()
{
execlp("ls","ls","-l",NULL);
return 0;
}
3>int execle(const char* path,const char* grg,...,char* const envp[])
hello.c
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 int main()
5 {
6 printf("houcong=%s\n",getenv("houcong"));
7 printf("hello world\n");
8 return 0;
9 }
exec.c
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 char* envp[] = {"houcong=0630",NULL};
7 execle("./hello","./hello",NULL,envp);
8 return 0;
9 }
4>int execv(const char* path,const char* argv)
int main()
{
char* argv[] = {"ls","-l",NULL};
execv("/bin/ls",argv);
return 0;
}
5>int execvp(const char* file,const char* argv)
#include<stdio.h>
#include<unistd.h>
int main()
{
char* argv[] = {"ls","-l",NULL};
execvp("ls",argv);
}
功能:让进程执行ls -l命令
6>int execve(const char* path,const char* argv,char* const envp[])
1 #include<stdio.h>
2 #include<unistd.h>
3
4 int main()
5 {
6 char* argv[] = {"./hello",NULL};
7 char* envp[] = {"houcong=222",NULL};
8 execve("./hello",argv,envp);
9 return 0;
10 }