exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用内部执行一个可执行文件
exec函数族的函数执行成功后不会反悔,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样。只有调用失败了,他们才会返回-1,从源程序的调用点接着往下执行
前6个都是C库的函数,只有最后一个是Linux的函数
前2个是最常用的
#include
extern char **environ;
int execl(const char *pathname, const char *arg, …);
参数:
返回值:
只要当调用失败时,才会有返回值,返回-1,并且设置errno
如果调用成功,没有返回值
#include
#include
int main(){
//创建一个子进程,在子进程中执行exec函数族中的函数
pid_t pid = fork();
if(pid > 0){
//父进程
printf("i am parent process,pid : %d\n",getpid());
sleep(1);
}else if(pid == 0){
//子进程
//execl("hello", "hello",NULL);
execl("/bin/ps","ps","a","u","x",NULL);
printf("i am child process,pid = %d\n",getpid());
}
for(int i = 0;i < 3;i++){
printf("i = %d,pid = %d\n",i,getpid());
}
return 0;
}
#include
extern char **environ;
int execl(const char *pathname, const char *arg, …);
int execlp(const char *file, const char *arg, …);
会到环境变量中查找指定的可执行文件,如果找到了就执行,找不到就执行不成功。
参数:
返回值:
只要当调用失败时,才会有返回值,返回-1,并且设置errno
如果调用成功,没有返回值
#include
#include
int main(){
//创建一个子进程,在子进程中执行exec函数族中的函数
pid_t pid = fork();
if(pid > 0){
//父进程
printf("i am parent process,pid : %d\n",getpid());
sleep(1);
}else if(pid == 0){
//子进程
//execl("hello", "hello",NULL);
execlp("ps","ps","a","u","x",NULL);
printf("i am child process,pid = %d\n",getpid());
}
for(int i = 0;i < 3;i++){
printf("i = %d,pid = %d\n",i,getpid());
}
return 0;
}
int execlp(const char *file, const char *arg, …);
int execle(const char *pathname, const char *arg, …);
char *envp[] = {“/home/Liunx”,“/home/bbb”,“/home/aaa”};
int execv(const char *pathname, char const argv[]);
argv是需要的参数的一个字符串数组
char argv[] = {“ps”,“aux”,NULL}
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
#include
void exit (int status);
#include
void _exit(int status);
#include
#include
#include
int main(){
printf("hello\n");
printf("world");
//exit(0);
_exit(0);
return 0;
}
如果是exit()函数,则会打印world,而_exit()并不会
因为c库的exit()函数会多做两部事,其中刷新缓冲区就会将缓冲区里没输出的world输出
这里拿之前的fork()函数相关代码来改
#include
#include
#include
int main(){
//创建子进程
pid_t pid = fork();
//判断是父进程还是子进程
if(pid > 0){
printf("i am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
}else if(pid == 0){
sleep(1);
//当前是子进程
printf("i am child process ,pid: %d,ppid :%d\n",getpid(),getppid());
}
//for循环
for(int i = 0;i < 5;i++){
printf("i:%d\n",i);
}
return 0;
}
在子进程sleep后,父进程早已执行完被释放,这时子进程就变成了孤儿进程,查看它的ppid为1,说明被init接管,且会进入前台,而不是和父进程共享
依然是拿那段代码来改,当父进程进入死循环,而子进程就会执行完变成僵尸进程,新开一个命令行窗口,没办法通过kill命令来杀死它
我们可以通过ctrl+c来强行杀死父进程,这样子进程也会消失
#include
#include
#include
int main(){
//创建子进程
pid_t pid = fork();
//判断是父进程还是子进程
if(pid > 0){
while(1){
printf("i am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
}else if(pid == 0){
sleep(1);
//当前是子进程
printf("i am child process ,pid: %d,ppid :%d\n",getpid(),getppid());
}
//for循环
for(int i = 0;i < 5;i++){
printf("i:%d\n",i);
}
return 0;
}
#include
#include
pid_t wait(int *wstatus);
功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收子进程的资源、
参数:int *wstatus
进程退出时的状态信息,传入的是一个int类型的地址,传出参数
返回值:
调用wait函数的进程会被挂起(阻塞),直到它的一个子进程退出或者受到一个不能被忽略的信号时才被唤醒(相当于继续往下执行)
如果没有子进程了,函数立刻返回,返回-1;如果子进程都已经结束了,也会立即返回-1
pid_t waitpid(pid_t pid, int *wstatus, int options);
#include
#include
#include
#include
#include
int main(){
//有一个父进程,创建5个子进程(兄弟)
pid_t pid;
//创建5个子进程
for(int i = 0; i < 5;i++){
pid = fork();
if(pid == 0){
break;
}
}
if(pid > 0){
//父进程
while ((1))
{
printf("parent,pid = %d\n",getpid());
//int ret = wait(NULL);
int st;
int ret = wait(&st);
if(ret == -1){
break;
}
if(WIFEXITED(st)){
//是不是正常退出
printf("退出的状态码:%d\n",WEXITSTATUS(st));
}
if(WIFSIGNALED(st)){
//是不是异常终止
printf("被哪个型号干掉了:%d\n",WTERMSIG(st));
}
printf("child dir,pid = %d\n",ret);
sleep(1);
}
}else if(pid == 0){
//子进程
// while (1)
// {
printf("child,pid = %d\n",getpid());
sleep(1);
//}
exit (0);
}
return 0;
}
#include
#include
pid_t waitpid(pid_t pid, int *wstatus, int options);
功能:回收指定进程号的子进程,可以设置是否阻塞
参数:
返回值:
> 0:返回子进程的id
= 0:options = WNOHANG,表示还有子进程活着
= -1:错误,或者没有子进程了
wait(&wstatus) == waitpid(-1,&wstatus,0);
#include
#include
#include
#include
#include
int main(){
//有一个父进程,创建5个子进程(兄弟)
pid_t pid;
//创建5个子进程
for(int i = 0; i < 5;i++){
pid = fork();
if(pid == 0){
break;
}
}
if(pid > 0){
//父进程
while ((1))
{
printf("parent,pid = %d\n",getpid());
sleep(1);
//int ret = wait(NULL);
int st;
//int ret = waitpid(-1,&st,0);
int ret = waitpid(-1,&st,WNOHANG);
if(ret == -1){
break;
} else if(ret == 0){
//说明还有子进程存在
continue;
}else if(ret > 0){
if(WIFEXITED(st)){
//是不是正常退出
printf("退出的状态码:%d\n",WEXITSTATUS(st));
}
if(WIFSIGNALED(st)){
//是不是异常终止
printf("被哪个型号干掉了:%d\n",WTERMSIG(st));
}
}
printf("child dir,pid = %d\n",ret);
}
}else if(pid == 0){
//子进程
while (1)
{
printf("child,pid = %d\n",getpid());
sleep(1);
}
exit (0);
}
return 0;
}
子进程和父进程在运行时交替运行,在子进程被逐个kill后,父进程这边会显示被-9型号干掉了,当所有的子进程都被kill了之后,父进程会退出