--如果父进程没有调用wait()和waitpid()函数,子进程就会进入僵死状态。
--如果父进程调用了wait()和waitpid()函数,就不会使子进程变为僵尸进程。
这是为什么呢?现在我们来深入学习wait()函数和waitpid()函数。
|
一.wait()和waitpid()学习
1.首先我们先看一下它们的函数原型:
在终端输入命令:man 2 wait
就会看到它的函数原型:
NAME
SYNOPSIS
我们可以看到在2.6版本中新增叫了waitid()函数。
2.wait()和waitpid()的功能:
1>wait()函数使父进程暫停执行,直到它的一个子进程结束为止,该函数的返回值是终止运行的子进程的PID. 参数status所指向的变量存放子进程的退出码,即从子进程的main函数返回的值或子进程中exit()函数的参数。如果status不是一个空指针,状态信息将被写入它指向的变
量。
2> 头文件sys/wait.h中定义了进程退出状态的宏。
我们首先看下官方的解释
a.WIFEXITED(status)
Tiger-John翻译:
WIFEXITED(status)
b. WEXITSTATUS(status)
Tiger-John翻译:
WEXITSTATUS(status)
c.W IFSIGNALED(status)
Tiger-John翻译:
WIFSIGNALED(status)
d. WTERMSIG(status)
Tiger-John翻译:
WTERMSIG(status)
e.WIFSTOPPED(status)
Tiger-John翻译:
WIFSTOPPED(status)
f. WSTOPSIG(status)
Tiger-John翻译:
WSTOPSIG(status)
g.WIFCONTINUED(status)
resumed by delivery of SIGCONT.
Tiger-John翻译:
WIFCONTINUED(status)
值。
3>waitpid() 函数
(1)我们先来看一个waitpid()的经典例子:当我们下载了A软件的安装程序后,在安装快结束时它又启动了另外一个流氓软件安装程序B,当B也安装结束后,才告诉你所有安装都完成了。A和B分别在不同的进程中,A如何启动B并知道B安装完成了呢?可以很简单地在A中用fork启动B,然后用 waitpid()来等待B的结束。
(2)waitpid()也用来等待子进程的结束,但它用于等待某个特定进程结束。参数pid指明要等待的子进程的PID,参数 status的含义与wait()函数中的 status相同。options参数可以用来改变waitpid的行为,若将该参数赋值为WNOHANG,则使父进程不被挂起而立即返回执行其后的代
码。
(3)waitpid()函数中参数pid的取值
还是先看下官方解释:
Tiger-John翻译:
pid的值可以为下己中情况:
< -1
=-1
=0 等待其组ID等于调用进程的组ID的任一进程
> 0
(4)waitpid()函数的一个应用:
如果想让父进程周期性地检查某个特定的子进程是否已经退出,可以用下面的方法:
waitpid(child_pid,(int *) 0,WNOHANG);
如果子进程尚未退出,它将返回0;如果子进程已经结束,则返回child_pid。调用失败时返回-1。失败的原因包括没有该子进程,参数不合法等。
3.wait()和 waitpid() 函数的区别
(1). 在一个子进程终止前,wait()使其调用者阻塞,而waitpid()有一个选项,可使调用者不阻塞。
(2). waitpid()并不等待在其调用之后的第一个终止子进程,它有若干个选项,可以控制它所等待的进程。
(3). 对于wait(),其唯一的出错是调用进程没有子进程;对于waitpid(),若指定的进程或进程组不存在,或者参数pid指定的进程不是调用进程的子进程都可能出错。
(4). waitpid()提供了wait()没有的三个功能:一是waitpid()可等待一个特定的进程;二是waitpid()提供了一个wait()的非阻塞版本(有时希望取的一个子进程的状态,但不想使父进程阻塞,waitpid() 提供了一个这样的选择:WNOHANG,它可以使调用者不阻塞);三是waitpid()支持作业控制。
(5)
函数实例: 有时希望取的一个子进程的状态,但不想使父进程阻塞,waitpid() 提供了一个这样的选择:WNOHANG,它可以使调用者不阻塞
do{
pr=waitpid(pc, NULL, WNOHANG);
}while(pr==0);
if(pr==pc)
else
Tiger-John总结
无论进程是否正常终止,内核都会向其父进程发送SIGCHLD 信号, 当调用wait或waitpid函数时
(a) 如果所有的子进程都在run, 可以阻塞父进程。
(b) 如果子进程终止,则wait立即返回子进程终止状态。
(c) 如果没有子进程在运行, 立即返回error。
4.函数实现:
函数实例 1.(先看一个简单的实例,看看进程调用wait()函数后是如何执行的?)
函数经过编译:
think@ubuntu:~/work/process_thread/wait$ gcc wait.c -o wait
think@ubuntu:~/work/process_thread/wait$ ./wait
函数执行结果:
this is the father process,ppid=3303
father wait the child end
this is the child process pid= 3356
this is the child process print 1 !
this is the child process print 2 !
this is the child process print 3 !
this is the child process print 4 !
this is the child process print 5 !
the child end
father end
Tiger-John说明:
从上面的程序我们可以深入的了解wait() 函数的执行过程:
当父进程调用wait()函数后被挂起等待,直到子进程结束为止。
函数实例2(现在我们在通过一个实例,来深入了解wait()函数的执行过程)
函数进过编译后:
think@ubuntu:~/work/process_thread/wait$ gcc wait1.c -o wait1
think@ubuntu:~/work/process_thread/wait$ ./wait1
函数执行结果 :
tiger study how to get exit code
child process has exited,pid = 3816
child exited with code 0
Tiger-John说明:
父进程调用wait()函数后被挂起(我们可以再开一个终端,输入命令:ps aux,可以看到父进程的执行结果为S)直到子进程结束。子进程结束后,wait()函数返回刚刚结束运行的子进程的pid,宏WEXITSTATUS获取子进程的退出码。