fork之续---wait和waitpid

前言

进程运行的时候要占用资源的,当他们运行完之后要释放资源出来,如果没释放的话就叫做僵尸进程。

DESCRIPTION
All of these system calls are used to wait for state changes in a
child of the calling process, and obtain information about the child
whose state has changed. A state change is considered to be: the
child terminated; the child was stopped by a signal; or the child was
resumed by a signal. In the case of a terminated child, performing a
wait allows the system to release the resources associated with the
child; if a wait is not performed, then the terminated child remains
in a “zombie” state (see NOTES below).

然后子进程呢是要父进程来帮忙“收尸”(释放)的,如果父进程比子进程先执行完的话,那么子进程就会变成孤儿进程,然后系统就会把它归到user项里面,让user“收养”它。
wait和waitpid就是用来给父进程去收尸用的。

wait

SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>

   pid_t wait(int *wstatus);

   pid_t waitpid(pid_t pid, int *wstatus, int options);

RETURN VALUE
wait(): on success, returns the process ID of the terminated child; on
error, -1 is returned.

要保证能够正常用wait来回收子进程的话,必须要让子进程先执行完,然后再到父进程执行完,不然的话子进程就变孤儿进程了。
但是实际测试的时候不是这样的,怎么说呢,wait是阻塞式的,如果子进程没结束的话,它会等待子进程结束之后再执行的。
测试的时候我在子进程执行之前加了sleep(1),我以为是直接父进程运行完就完事了,后面才发现原来wait是阻塞式的,会一直等那个wstatus

代码

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>

/*
void prt(void)
{
	
	printf("会调用两次执行两次\n");
}
*/

int main(int argc,char **argv)
{
	if(argc != 2)
	{
		printf("usage: ./a.out filename\n");
		exit(-1);
	}
	else
	{
		pid_t ret = -1;
		ret = fork();
		
		if (ret > 0)
		{
			
			printf("父进程\n");
			printf("the ret of parent means its child pid = %d\n",ret);
			printf("my own id is  = %d\n",getpid());
			int wstatus = -1;
			pid_t retw = -1;
			retw = wait(&wstatus);
			if(-1 == retw)
			{
				perror("wait");
			}
			else
			{
				printf("子程序被正常回收,子程序的process ID是%d\n",retw);
				printf("wstatus = %d\n",wstatus);
				int retr =  WIFEXITED(wstatus);
				printf("teriminated normally %d\n",retr);

			}
			return 0;
			
		}
		else if (0 == ret)
		{
			sleep(1);
			printf("子进程\n");
			printf("child ret = %d\n",ret);
			printf("child pid is  = %d\n",getpid());
			printf("my parent pid is  = %d\n",getppid());
		}
		else if (-1 == ret)
		{
			perror("fork");
			return -1;
		}
		
	}
	//atexit(prt);
	return 0;
}

watipid

SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>

   pid_t waitpid(pid_t pid, int *wstatus, int options);

The value of pid can be:

   < -1   meaning  wait  for  any child process whose process group ID is
          equal to the absolute value of pid.

   -1     meaning wait for any child process.

   0      meaning wait for any child process whose process  group  ID  is
          equal to that of the calling process.

   > 0    meaning  wait  for  the  child whose process ID is equal to the
          value of pid.

pid = -1、0还有>0都好理解,但是<-1不怎么懂。

The value of options is an OR of zero or more of the following con‐
stants:

   WNOHANG     return immediately if no child has exited.

   WUNTRACED   also  return  if  a  child has stopped (but not traced via
               ptrace(2)).  Status for traced children which have stopped
               is provided even if this option is not specified.

   WCONTINUED (since Linux 2.6.10)
               also  return if a stopped child has been resumed by deliv‐
               ery of SIGCONT.

option如果是0的话就是默认方式,阻塞式的,像wait一样,如果是WNOHANG (wait-no-hang)就变成非阻塞式了。

	retw = waitpid(-1,&wstatus,WNOHANG);
			if(-1 == retw)
			{
				perror("wait");
			}
			else
			{
				printf("子程序被正常回收,子程序的process ID是%d\n",retw);
				printf("wstatus = %d\n",wstatus);
				int retr =  WIFEXITED(wstatus);
				printf("teriminated normally %d\n",retr);

			}

这个代码块就是改成wait no hang的 结果如下
在这里插入图片描述
可以看到不是正常回收的,因为返回值的子程序id是0,没有返回到子程序的id,而且判断的时候terminated normally是0 证明不是正常回收的,就是非阻塞式的,这个就是父进程先执行完了。
如果把sleep(1)放到父进程前面,先让子进程先执行完的话就显示正常了
或者把WNOHANG改回0,默认值,那么它的工作情况就像wait那样阻塞,等有子进程结束才会继续执行。

还有

WIFEXITED宏用来判断子进程是否正常终止(return、exit、_exit退出)
这个在上面代码有演示的;
WIFSIGNALED宏用来判断子进程是否非正常终止(被信号所终止)
这个的话如果是正常终止的话应该是显示0,非正常才是·1
WEXITSTATUS宏用来得到正常终止情况下的进程返回值的。
这个的话WEXITSTATUS(wstatus)返回的值就是子程序最后return的值。
在这里插入图片描述在这里插入图片描述

总结

虽然有点乱,但是通过自己重新写代码然后再现课程的内容也是一种锻炼,并且加深印象啦。

补充一下,后面几天回来再看的时候突然不知道wstatus是什么了,后面看了一下man手册,wstatus的作用是用来存储wati()或者wait_pid()的状态信息的,所以我们传的是wstatus的地址,让数据传到这个地址里面,所以开始初始化的-1变成了后面的8448。
然后后面的WIFEXIT、WIFSIGNALED等等就根据这个status值来进行相关的判断。

If wstatus is not NULL, wait() and waitpid() store status information
in the int to which it points.

发布了38 篇原创文章 · 获赞 1 · 访问量 1038

猜你喜欢

转载自blog.csdn.net/qq_40897531/article/details/103838331