C/C++ 进程的探索(fork函数)

本次实验目的是学习进程fork函数的使用以及注意事项。

实验环境为ubuntu16.04 编译器是gcc 5.4

废话不多说,先上代码了。一会解释。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#define ERR_EXIT(m)			\
	do						\
	{						\
		perror(m);			\
		exit(EXIT_FAILURE);	\
	}while(0)

int main()
{
	printf("before fork pid = %d\n",getpid());
	pid_t pid;
	pid = fork();
	if(pid == -1)
	{
		ERR_EXIT("fork error");
	}
	if(pid > 0)
	{
		printf("this is pareent pid = % d childpid = %d\n",getpid(),pid);
	}else if(pid == 0)
	{
		printf("this is child = %d parentpid = %d \n",getpid(),getppid());
	}
	return 0;
}

解释一下主函数下第一行代码,

printf("before fork pid = %d\n",getpid());

这行代码是打印当前程序得进程号,getpid()是获取当前程序得进程号,并且打印出来。想要查看getpid函数可以man 2 getpid 一下。

pid = fork();

这句代码是复制进程的函数,

当复制进程成功,子进程返回0,父进程返回子进程的ID,失败返回-1.

这又有下面的代码

if(pid == -1)
	{
		ERR_EXIT("fork error");
	}
	if(pid > 0)
	{
		printf("this is pareent pid = % d childpid = %d\n",getpid(),pid);
	}else if(pid == 0)
	{
		printf("this is child = %d parentpid = %d \n",getpid(),getppid());
	}

如果pid == -1 打印错误信息。如果pid > 0 打印父进程ID和pid(也就是子进程ID)如果 pid == 0 打印子进程ID和父进程ID

其中getppid函数是获取父进程ID的函数

这个是打印结果,很奇怪。

第一个奇怪点,打印了三行。

按以前的思维pid只有一种状态要么大于0要么等于0,怎么会执行两者都执行了。这个说起了就是fork函数的关系, fork函数创建了一个子进程。那么 pid == 0 的代码是要在子进程中执行的,pid > 0是要在父进程中执行的。可以理解为CPU同一时间干了两件事,事实上并不是这样,事实上是cpu切换进程来实现的,比如干一件事干了1ms切换到第二件事干了1ms又切换到第一件事,这样来回切换,给人的感觉就是cpu在同时干两件事。这就是为什么可以输出三行。

fork函数一次调用两次返回。两个是在各自的地址空间返回的。

还有一个奇怪的地方那就是为什么子进程中的父进程是1 不应是7807吗?这个是因为父进程先执行完,执行完的进程及退出了,吧子进程托孤给1号进程。所以就出现这个现象,假如子进程先执行完,父进程在执行完就不会这样了。下面我们可以让父进程睡眠1S试试,这样父进程就不会比子进程先执行完。

先上代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#define ERR_EXIT(m)			\
	do						\
	{						\
		perror(m);			\
		exit(EXIT_FAILURE);	\
	}while(0)

int main()
{
	printf("before fork pid = %d\n",getpid());
	pid_t pid;
	pid = fork();
	if(pid == -1)
	{
		ERR_EXIT("fork error");
	}
	if(pid > 0)
	{
		sleep(1);
		printf("this is pareent pid = % d childpid = %d\n",getpid(),pid);
	}else if(pid == 0)
	{
		printf("this is child = %d parentpid = %d \n",getpid(),getppid());
	}
	return 0;
}

看结果:

本次代码只在上次代码基础上增加了一行代码:

那就是sleep(1);

这行代码的意思是睡眠1s的意思,延迟父进程的时间。 

僵尸进程:子进程先退出,父进程尚未查询子进程退出状态,子进程就是僵尸状态。

修改sleep(100)子进程为8029 父进程为8028

查看子进程用  ps -ef 查看

 

其中<defunct>的意思就是僵尸进程。

如何避免僵尸进程:

只需要添加一个信号即可,

#include <signal.h>

在main函数下添加

signal(SIGCHLD,SIG_IGN);

即可避免僵尸进程;

上代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <signal.h>
#define ERR_EXIT(m)			\
	do						\
	{						\
		perror(m);			\
		exit(EXIT_FAILURE);	\
	}while(0)

int main()
{
	signal(SIGCHLD,SIG_IGN);
	printf("before fork pid = %d\n",getpid());
	pid_t pid;
	pid = fork();
	if(pid == -1)
	{
		ERR_EXIT("fork error");
	}
	if(pid > 0)
	{
		sleep(100);
		printf("this is pareent pid = % d childpid = %d\n",getpid(),pid);
	}else if(pid == 0)
	{
		printf("this is child = %d parentpid = %d \n",getpid(),getppid());
	}
	return 0;
}

这就是结果僵尸进程已经不见了。 

总结:

父进程先退出,子进程成为孤儿进程。子进程先退出,父进程没有察觉到,子进程会成为僵尸进程。

猜你喜欢

转载自blog.csdn.net/m0_38036750/article/details/85265332
今日推荐