实验1:execl 使用,必加 fflush()刷新流
实验2:fork() execl() wait() 联合使用
few:fork + exec + wait
引子:
运行如下程序,执行 ps axf 命令查看 得到如下 父子进程关系:
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#define LEFT 200
#define RIGHT 250
int main(void)
{
int i,j,mark;
pid_t pid;
for(i = LEFT; i <= RIGHT; i++)
{
pid = fork();
if(pid < 0)
{
fprintf(stderr,"fork() failed!\n");
exit(1);
}
else if(pid == 0)//child
{
mark = 1;
for(j = 2; j < i/2; j++)
{
if(i % j ==0)
{
mark = 0;
break;
}
}
if(mark)
printf("%d is a primer\n",i);
exit(0);//!!!
}
}
sleep(1000);
exit(0);
}
2837 pts/0 Ss 0:01 | \_ /bin/bash
26731 pts/0 S+ 0:00 | | \_ ./a.out
26732 pts/0 Z+ 0:00 | | \_ [a.out] <defunct>
26733 pts/0 Z+ 0:00 | | \_ [a.out] <defunct>
26734 pts/0 Z+ 0:00 | | \_ [a.out] <defunct>
26735 pts/0 Z+ 0:00 | | \_ [a.out] <defunct>
....
可以看到
shell 进程是 a.out 进程的父进程
a.out 父进程是 其余201个a.out进程的父进程
问题1: 关于shell进程 和 a.out进程之间的关系
那么问题来了,a.out 和 他fork出来的201个 a.out之间的关系很好理解。但是 shell进程 与 a.out父进程之间的关系 怎么理解呢?
我们之前了解到,父进程与子进程之间的关系 是通过复制父进程本身来得到子进程 ,fork() 之后 子进程和父进程代码和执行的位置都是一模一样,只不过父子进程再向下执行的时候 就会根据自己的身份 来选择 预先设定好的 自己需要执行的代码。那么 为什么 shell 进程 和 a.out进程是不一样的,按理说 shell 进程 的子进程应该也是 shell进程,现在 a.out 很明显是和 shell 不一样的。此处该怎么理解呢?
exec函数族:
NAME
execl, execlp, execle, execv, execvp, execvpe - execute a file 执行一个文件!!!
SYNOPSIS
#include <unistd.h>
extern char **environ;
//以NULL 结尾,代表当前传参结束
int execl(const char *path, const char *arg, ...
/* (char *) NULL */);
int execlp(const char *file, const char *arg, ...
/* (char *) NULL */);
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
char *const envp[]);
The exec() family of functions replaces the current process image with a new process image.
exec 函数族用一个新的进程映像替换当前的进程映像
并没有创建新进程,只是替换一个进程。
RETURN VALUE
The exec() functions return only if an error has occurred. The return value is -1, and errno is set to indicate the error.
exec只有执行失败的时候才有返回值。
实验1:exec 初体验, 与缓冲区之间的联系 一定注意 fflush()
命令:date +%s :指定格式获取当前时间
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
int i,j,mark,n;
pid_t pid;
puts("Begin!");//puts() 输出时会自动换行
//以NULL 结尾,代表当前传参结束
execl("/bin/date","date","+%s",NULL);
perror("execl");//如果执行到此 说明 exec替换失败
exit(1);
puts("End!\n");
exit(0);
}
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out
Begin!
1613136072
mhr@ubuntu:~/Desktop/xitongbiancheng/test$
mhr@ubuntu:~/Desktop/xitongbiancheng/test$
mhr@ubuntu:~/Desktop/xitongbiancheng/test$
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out > /tmp/out
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ cat /tmp/out
1613136191
mhr@ubuntu:~/Desktop/xitongbiancheng/test$
结果和预料一样,程序执行到 exec()的时候,当前进程被替换成了 date进程
注意:在命令行执行可执行程序时候,打印了 Begin, 而重定位到 /tmp/out后 则不会打印Begin。
why???
在命令行执行的时候 puts是输出到终端,即标准输出,是行缓冲,故有Begin 打印。而重定位到 /tmp/out 则 puts 是输出到 全缓冲文件,换行符没有刷新缓冲区的作用,只是存储到缓冲区,而还没来得及刷新 就执行了 execl() ,即 date进程映像替换了当前进程映像,缓冲区信息也被覆盖了。所以 一定要注意 :
fork()之前 要 fflush(NULL)
execl() 之前 要 fflush(NULL)
刷新缓冲区!!!
即:
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
int i,j,mark,n;
pid_t pid;
puts("Begin!");//puts() 输出时会自动换行
fflush(NULL);
execl("/bin/date","date","+%s",NULL);
perror("execl");//如果执行到此 说明 exec替换失败
exit(1);
puts("End!\n");
exit(0);
}
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out > /tmp/out
mhr@ubuntu:~/Desktop/xitongbiancheng/test$
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ cat /tmp/out
Begin!
1613136824
mhr@ubuntu:~/Desktop/xitongbiancheng/test$
实验1中 用一个新的进程映像 替换 自己费心费力写出来的当前进程映像 没有任何意义,那还不如直接就用新的进程,所以 exec 主要应用在哪里呢??
实验2:exec的意义,fork() exec() wait() 三板斧使用:铺天盖地
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
int i,j,mark,n;
pid_t pid;
puts("Begin!");
fflush(NULL);
pid = fork();
if(pid < 0)
{
perror("fork()");
exit(1);
}
else if(pid == 0) //child 用子进程替换 date
{
fflush(NULL);
execl("/bin/date","date","+%s",NULL);
perror("execl");
exit(1);
}
wait(NULL);
puts("End!");
exit(0);
}
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ gcc test.c
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out
Begin!
1613137594
End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ ./a.out > /tmp/out
mhr@ubuntu:~/Desktop/xitongbiancheng/test$ cat /tmp/out
Begin!
1613137607
End!
mhr@ubuntu:~/Desktop/xitongbiancheng/test$
父进程 负责创建 子进程。子进程负责干活,即替换为 date 进程,最后父进程等着释放子进程资源。
所以这里就解释了 问题1的问题
关于shell进程 和 a.out进程之间的关系。很明显 shell进程中 的一个子进程映像 替换成了 a.out 进程映像!!!