Linux并发程序设计_wait()和waitpid()-02

进程回收

子进程结束时由父进程回收

孤儿进程由init进程回收

若没有及时回收会出现僵尸进程

wait()和waitpid()

(1)函数说明:
wait()函数用于使父进程(也就是调用 wait()的进程)阻塞(暂时停止目前进程的执行),直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则 wait()会立即返回-1。子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回。如果不在意结束状态值, 则参数status可以设成NULL。

阻塞(pend)就是任务释放CPU,其他任务可以运行,一般在等待某种资源或信号量的时候出现。挂起(suspend)不释放CPU,如果任务优先级高就永远轮不到其他任务运行,一般挂起用于程序调试中的条件中断,当出现某个条件的情况下挂起,然后进行单步调试。

waitpid()的作用和 wait()一样,但它并不一定等待第一个终止的子进程。waitpid()有若干选项,可提供一个非阻塞版本的 wait()功能。实际上 wait()函数只是 waitpid()函数的一个特例,在 Linux 内部实现 wait()函数时直接调用的就是 waitpid()函数。

wait()函数族语法

头文件 #include <sys/types.h>
#include <sys/wait.h>
函数原型 pid_t wait(int *status);
函数传入值 status 指向的整型对象用来保存子进程结束时的状态。另外,子进程的结束状态可由 Linux 中一些特定的宏来测定
函数返回值 成功:已回收的子进程的进程号
失败:-1

在这里插入图片描述
子进程通过exit / _exit / return 返回某个值(0-255)
父进程调用wait(&status) 回收

WIFEXITED(status)   判断子进程是否正常结束
WEXITSTATUS(status) 获取子进程返回值
WIFSIGNALED(status)判断子进程是否被信号结束
WTERMSIG(status)   获取结束子进程的信号类型;

 int main(int argc, const char *argv[])
{
	pid_t pid;
	int status,i;
	if(fork() == 0)
	{
		printf("This is the child process .pid =%d\n",getpid());
		exit(5); // 子进程的返回值
	}
	else
	{
		sleep(1);
		printf("This is the parent process ,wait for child...\n");
	
		pid=wait(&status);// 获取回收子进程的的进程号
		i=WEXITSTATUS(status);//获取子进程返回值
		printf("child's pid =%d .exit status= %d\n",pid,i);
	}
	return 0;
}

在这里插入图片描述
waitpid()函数语法

头文件 #include <sys/types.h>
#include <sys/wait.h>
函数原型 pid_t waitpid(pid_t pid, int *status, int options);
函数传入值 pid
pid > 0:回收进程 ID 等于 pid 的子进程
pid = 1:回收任何一个子进程,此时和 wait()作用一样
pid = 0:回收其组 ID 等于调用进程的组 ID 的任一子进程
pid < 1:回收其组 ID 等于 pid 的绝对值的任一子进程
函数传入值 status : 同 wait()
options:
WNOHANG:若指定的子进程没有结束,则 waitpid()不阻塞而立即返回,此时返回值为 0
WUNTRACED:为了实现某种操作,由 pid 指定的任一子进程已被暂停,且其状态自暂停以来还未报告过,则返回其状态
0:同wait(),阻塞父进程,直到指定的子进程退出
函数返回值 >0:已经结束运行的子进程的进程号
0:使用选项 WNOHANG 且没有子进程退出
-1:出错

waitpid()使用示例。
由于 wait()函数的使用较为简单,在此以 waitpid()为例进行讲解。本例中首先使用 fork()创建一个子进程,然后让子进程暂停 5s(使用了 sleep()函数)。接下来对原有的父进程使用 waitpid()函数,并使用参数 WNOHANG 使该父进程不会阻塞。若有子进程退出,则 waitpid()返回子进程号;若没有子进程退出,则 waitpid()返回 0,并且父进程每隔 1s 循环判断一次
在这里插入图片描述

int main(int argc, const char *argv[])
{
	pid_t pid, ret;
	
	pid = fork();

	if(pid < 0 )
	{
		printf("Error fork\n");
	}
	else if (pid == 0)/*子进程*/
	{
		/*子进程暂停 5s*/
		sleep(5);
		/*子进程正常退出*/
		exit(0);
	}
	else/*父进程*/
	{
		/*循环测试子进程是否退出*/
		do
		{
			/*调用 waitpid,且父进程不阻塞*/
			ret = waitpid(pid, NULL, WNOHANG);
	
			/*若子进程还未退出,则父进程暂停 1s*/
			if(ret == 0)
			{
				printf("The child process has not exited \n ");
				sleep(1);
			}
		}while(ret == 0);
	
		/*若发现子进程退出,打印出相应情况*/
		if(pid == ret)
		{
			printf(" The child process exited \n");
		}
		else
		{
			printf("some error  occured \n");
		}
	}

	return 0;
}

在这里插入图片描述
如果把 ret = waitpid(pid, NULL, WNOHANG); 改为 ret = waitpid(pid, NULL, 0); 父进程会一直阻塞,直到子进程结束为止,运行的结果如下。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Set_Mode/article/details/89922555