Linux系统编程38 进程控制 - exec函数族 必加fflush,搭配fork+execl+wait

实验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;

   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() 输出时会自动换行

	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 进程映像!!!

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/113797632
今日推荐