一、exec函数族----启动一个新程序
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),
子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的
用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建
新进程,所以调用exec前后该进程的id并未改变。
其实有六种以exec开头的函数,统称exec函数:
1.execl execv
int exec l(const char *path, const char *arg, ...);
要运行文件的路径 要执行的文件名 要执行文件需要的参数
以NULL结尾
int exec v(const char *path, char *const argv[]);
将除了文件路径的其他放入char *const argv[]中。
l --- list //ls -l /
path ---文件路径 "/bin/ls"
arg ---> 要执行的 文件的名字 "ls"
"-l" "/" NULL 表示结束
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
printf("---begin---\n");
//execl("/bin/ls","ls","-l",".",NULL);
//char * const arg[] ={"ls","-l",".",NULL};
//execv("/bin/ls",arg);
execl("/home/linux/linux_prog/01-prog/mycp","mycp","1.c","2.c",NULL);
printf("---end---\n");
return 0;
}
2.execlp execvp
int exec l p(const char *file, const char *arg, ...);
p-----表示要执行的文件,从PATH环境变量中去找。
出错才有返回值,返回值为-1,
int exec v p(const char *file, char *const argv[]);
和execv一致,除file其余放入char *const argv[]中
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
printf("---begin---\n");
//execl("/bin/ls","ls","-l",".",NULL);
//char * const arg[] ={"ls","-l",".",NULL};
//execv("/bin/ls",arg);
//execl("/home/linux/linux_prog/01-prog/mycp","mycp","1.c","2.c",NULL);
//if (execlp("mycp","mycp","1.c","2.c",NULL) < 0)
char *const arg[] = {"mycp","1.c","2.c",NULL};
if (execvp("mycp",arg) < 0)
{
perror("execl fail");
return -1;
}
printf("---end---\n");
return 0;
}
l 与 v 的区别后面参数是为数组(v)还是直接写入(l)。
3.execle execvpe
带e 表示的是可以给要执行的 新程序 传递需要的 环境变量
int execle (const char *path, const char *arg, ..., char * const envp[]);
要运行文件的路径 要执行的文件名 要执行文件需要的参数 环境变量
#include <stdio.h>
#include <unistd.h>
extern char **environ;
int main(int argc, const char *argv[])
{
char *menv[] = {"USER=linux","PASSWD=123456",NULL};
//execle("./myenv","myenv",NULL,environ);
//execle("./myenv","myenv",NULL,menv);
execle("./myenv","myenv",NULL,menv);
return 0;
}
environ:系统环境变量,环境变量可自定义,也可为NULL ,以下代码为系统环境变量
#include <stdio.h>
extern char **environ;
int main(int argc, const char *argv[])
{
int i = 0;
while (environ[i] != NULL)
{
printf("env[%d] = %s\n",i,environ[i]); //char *
++i;
}
return 0;
}
int execvpe(const char *file, char *const argv[] , char * const envp[]);
路径加文件名
1.带l的默认会搜索当前路径下。
2.带p的只搜索只搜索PATH系统环境变量
子进程做与父进程相同的事情------创建子进程,执行任务即可
子进程做与父进程不同的事情------fork + exec
二、进程的终止
1.main中返回ruturn
return 当该关键字出现在main函数中时候可以结束进程,如果在其他函数中则表示结束该函数
2.exit-----库函数
void exit(int status)
功能:让进程退出,并刷新缓存区
参数:status:进程退出的状态
返回值:缺省
会调用atexit函数
3._exit-----系统调用
void _exit(int status);
功能:让进程退出,不刷新缓存区
参数:status:进程退出状态
返回值:缺省
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
printf("hello world!\n");
exit(0); //(3)库函数
//_exit(0); //(2)系统调用
return 0;
}
4.atexit
int atexit(void (*function)(void));
功能:注册进程退出前执行的函数
参数:function:函数指针,指向void返回值void参数的函数指针
返回值:成功返回0,失败返回非0
当程序调用exit或者由main函数执行return时,所有用atexit
注册的退出函数,将会由注册时顺序倒序被调用
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void cleanup(void)
{
free(q);
printf("----cleanup---\n");
}
int main(int argc, const char *argv[])
{
atexit(cleanup);
printf("hello world!\n");
return 0;
}
异常退出 ---信号结束掉
abort signal
三、进程结束时的资源回收
1.wait
功能:1.获取子进程退出状态 。2.回收资源 //会让僵尸态的子进程销毁
注:wait的本身 是一个 阻塞操作 会使调用者 阻塞
父进程要获得子进程的退出状态
子进程 exit(退出状态值) 退出状态值 只有最低8位有效 [0~255]
父进程 wait(&status) 获取到退出状态值
WIFEXITED() 先判断是否为正常退出
WEXITSTATUS() 获取到exit传递的退出状态值
2.waitpid
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:等待子进程状态发生变化
参数: pid :pid = -1 //表示等待所有子进程 pid > 0 //表示等待 指定的子进程状态改变
wstatus //表示获取到 子进程 状态信息
options //选项 //可以不阻塞 WNOHANG //hang on
//默认是阻塞 0
wait(&wstatus) <=> waipid(-1,&wstatus,0)
非阻塞调用:waitpid(-1,&wstatus,WNOHANG); //表示非阻塞调用
非阻塞 和 阻塞
1.阻塞 会父进程处理逻辑
2.非阻塞 父进程 会去查看 子进程状态改变,但是,如果没有发生改变,父进程不阻塞,整个程序继续往下 。非阻塞 必须 套在循环中处理 //轮询 。
wait 和 waitpid都是 等待子进程状态改变
wait 是一种阻塞调用
waitpid 可以实现非阻塞调用
进程退出:处理方式
wait //阻塞方式 --- 调用进程 一般不做额外的事情
waitpid //非阻塞的方式 --- 调用进程 逻辑一般不受影响waitpid 想要处理到子进程
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
pid_t pid = fork();
if (-1 == pid)
{
perror("fork fail");
return -1;
}
if (pid > 0)
{
int status;
printf("father ----\n");
wait(&status);
printf("status = %d\n",status);
if (WIFEXITED(status))
{
printf("status = %d\n",WEXITSTATUS(status));
}
}else if (pid == 0)
{
printf("child exit \n");
exit(256);
}
return 0;
}