进程等待
进程等待就是为了同步父进程和子进程,如把运算放到子进程,赋值放到父进程,可能需要让父进程等待子进程运算结束.
一个进程
在
终止时会关闭所
有的文件描述符,释放在用户空间分配的内存,但他的PCB还保留着,内核在其中保存了一些信息:如
果是正常终
止则
保存着退出状态,如果是异常退
出则保存着导致该进程终止的信号是哪个. 这个进程的父进程可以调用wait或
waitpid获取这些
信息,
然后彻底消除掉这个进程。我们知道一个进程的
退出状态可以在shall中用特殊变量¥?查看,因为shell
是它的父进程,当
它终止时
Shell
调用wait或waitpid得到它的退出状态同时彻底清除这个进
程。
当一个进程正常或异常终止时,内核就向父进程发送一个SIGCHLD信号。因为子进程终止是一个异步时间,所以发生这种信号发生
也是
内核向父进程发
的异步通知。父进程可以选择忽略该信号,或者提供一个该信号发生时既被调用执行的函数。对于这种信号
的系统默
认
动作是忽略它。 而父进程如果
需要处理掉子进程就要调用wait和waitpid命令.
进程的三种基本状态
进程在运行中不断地改变其运行状态。通常,一个运行进程必须具有以下三种基本状态。
就绪状态:当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
执行状态:当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
阻塞状态:正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多
种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。
那么当父进程调用了wait和waitpid函数后,会发生什么情况呢?
如果其所有子进程都还在运行,则阻塞.
如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止态立即返回.
如果它没有任何子进程,则立即出错返回.
wait/waitpid函数:
#include<sys/wait.h>
wait函数:pid_t wait(int* status)
返回值: 成功返回被等待进程pid,失败返回-1.
参数:输出型参数,获取子进程退出的状态不关心设置空.
如果进程由于接收到SIGCHLD而调用wait,则会期望wait会立即返回.但如
果
在任意时刻调用
wait,则进程可能阻塞.
在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞.
如果
status不是一个空指针,则终止
进程的终止状态就存放它所指的单元内。 如果不关心终止状态,则可将该参数设为空指针.
waitpid函数: pid_t waitpid(pid_t pid,int *status,int options);
返回值:
1当正常返回时waitpid返回手机的子进程的进程ID
2.如果设置了选项WNOHANG,而调用中waitpid发现没有退出的子进程可手机,贼返回0.
3.如果调用出错返回-1
4.当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程waitpid就会出错返回,这是errno被设置为ECHILD 参数:
1.pid
pid = -1,等待任意个子进程
pid > 0,等待其进程ID与PID相等的子进程
pid = 0 等待其组ID等于调用进程组ID的任意意个子进程
pid < -1 等待其组ID等于PID绝对值的任意子进程
pid < -1 等待其组ID等于PID绝对值的任意子进程
2.status:
WIFEXITED: 若为正常终止子进程的方法返回状态贼为真.
WEXITSTATUS:若WIFEXITED,提取子进程的退出码.
WEXITSTATUS:若WIFEXITED,提取子进程的退出码.
3.options
WNOHANG:若pid指定的子进程还没有结束,则waitpid()函数返回0,不予以等待
若正常结束,则返回该子进程ID.(这里就是我上面说的waitpid的特殊选项)
若正常结束,则返回该子进程ID.(这里就是我上面说的waitpid的特殊选项)
代码验证:
接下来我们来看看代码的结果:
因为整个过程是一个动态过程,我就把前后结果贴出来就好~
5秒后->
这里就是阻塞等待,接下来我们来看看非阻塞等待。
非阻塞等待:
这个代码我们采用了非阻塞等待,也就是在等待的过程中父进程还在运行自己的代码,然后我们就可以通过程序运行后的结果,
很清晰的看到这个情况,现在看程序运行的结果:
我们很清晰的看到这里根据程序所表示的每隔一秒去看一下,然后再运行自己的程序,这种方式就是一个很节约时间的方式,我
们对待进程等待的理解应该更上一个层次了呢.这里进程等待的知识点大概就是这么多,我们认真理解一定可以熟练地掌握这个知识
点.
相关测试代码:
阻塞等待:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("%s fork error\n",__FUNCTION__);
return 1;
}
else if(pid == 0)
{
//child
printf("child is run,pid is:%d\n",getpid());
sleep(5);
exit(257);
}
else
{
int status = 0;
pid_t ret = waitpid(-1,&status,0);// wait 5s
printf("this is test for wait\n");
if(WIFEXITED(status)&&ret == pid)
printf("wait child 5s success,child return code is:%d\n",WEXITSTATUS(status));
else
{
printf("wait child failed,return \n");
return 1;
}
}
}
非阻塞等待:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main()
{
pid_t pid;
pid = fork();
if(pid < 0)
{
printf("%sfork error\n",__FUNCTION__);
return 1;
}
else if(pid == 0)
{
//child
printf("child is run,pid is: %d\n",getpid());
sleep(5);
exit(1);
}
else
{
int status = 0;
pid_t ret = 0;
do
{
ret = waitpid(-1,&status,WNOHANG);
printf("father do other thing\n");
if(ret == 0)
printf("child is runing\n");
sleep(1);
}while(ret == 0);
if(WIFEXITED(status)&& ret == pid)
printf("wait child 5s success,child return cod is:%d\n",WEXITSTATUS(status));
else{
printf("wait child failed,return\n");
return 1;
}
}
return 0;
}