Wait 函数|学习笔记

简介: 快速学习 Wait 函数

开发者学堂课程【物联网开发- Linux 高级程序设计全套视频Wait 函数】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/660/detail/10989


Wait 函数

 

内容简介:

一、wait 或 waitpid 的作用

二、代码实现的过程及内容

三、wait 的相关内容

四、取出子进程的退出状态

 

一、wait 或 waitpid 的作用

进程的等待,那父子进程有时候需要进行简单的进程间同步,比如父进程等待子进程结束,子进程结束了之后,父进程再去干它的事情,然后父进程等待子进程结束,那个等是用的wait或者waitpid ,这两个函数当中的其中一个都能去等待子进程结束,

注意一下 wait 和 waitpid 的作用,其实它有两个作用,一个是等,父进程调用  wait 之后,只能是父等子,即父进程等子进程,父进程的程序执行 wait 或者 waitpid 的时候有两个作用,一个是挂起,等待子进程结束,等子进程结束了之后,它再解除挂起,然后继续往下运行代码,即就在等;第二个作用就是回收子进程的资源,子进程结束了之后回收子进程的资源,如果不调用 wait 或者 waitpid 等子进程结束了,父进程还没结束,这属于什么?

没有调用 wait ,父进程没有结束,子进程已经结束了,这个情况子进程的资源就没有被回收,子进程就处于僵尸状态,所以有一个概念叫僵尸进程,那么什么叫做僵尸进程?

子进程已经结束了,父进程没有结束,而且父进程没有去调 wait 去回收它的资源。

 

二、代码实现的过程及内容

1、修改上节代码

在讲wait函数之前先把代码改一下,先输以下代码:

[01_day]./fork3

In write to stdout

Before fork

In son process

In father process

[01_day]./fork3 > aaa.txt

[01_day]vi aaa.txt

[01_day]cp fork.c wait.c

[01_day]vi wait.c

点执行之后代码如下所示:

/********************************************************

*       Filename:  fork.c

*     Description:

*         Version:   1.0

*         Created:   2019年01月08日 01时43分00秒

*        Revision:   none\

*        Compiler:   gcc

*          Author:   YOUR NAME().

*         Company:

**********************************************************

#include <unistd.h>

#include <stdio.h>

int main(int argc, char *argv[])

{

pid_t pid;

pid=fork();

if(pid<0)

{

perror(“fork”)

return 0;

}

else if(pid == 0)

{

while(1)

{

printf(“this is son process\n”);

sleep(1);

}

}

else

{

while(1)

}

2、再将代码中 while 循环改成 for 循环

可以看到子进程 while 循环,现将 while 循环改成 for 循环,如下所示:

/********************************************************

*       Filename:  fork.c

*     Description:

*         Version:   1.0

*         Created:   2019年01月08日 01时43分00秒

*        Revision:   none\

*        Compiler:   gcc

*          Author:   YOUR NAME().

*         Company:

**********************************************************

#include <unistd.h>

#include <stdio.h>

int main(int argc, char *argv[])

{

pid_t pid;

int i;

pid=fork();

if(pid<0)

{

perror(“fork”)

return 0;

}

else if(pid == 0)

{

//while(1)

for(i=0;i<5;i++)

{

printf(“this is son process\n”);

sleep(1);

}

}

else

while(1)

}

I 小于五, I 加加是让它循环五次,当然在此前要定义一个整形的变量 i ,如上所示般,那样子进程只能活五秒,而父进程一直在循环,父进程没有调 wait ,没有调 wait 它既不会等,也不会回收子进程的资源。

3、运行上述代码及说明

运行以上修改之后的代码,运行结果如下:

[01_day]./fork3

In write to stdout

Before fork

In son process

In father process

[01_day]./fork3 > aaa.txt

[01_day]vi aaa.txt

[01_day]cp fork.c wait.c

4、ps两个进程的状态及说明

可以看到前五秒的时候它俩都在,五秒钟之后子进程已经结束了,而父进程一直在执行,这时用 ps 来这两个进程的状态,

结果如下所示:

[~]ps -a

PID TTY      TIME CMD

6574 pts/0     00:00:00 wait

6575 pts/0     00:00:00 wait <defunct>

6763 pts/0     00:00:00 ps

可以看到父进程的进程号是6574,是一个正常的进程,而子进程还在,按理说这个时候子进程已经都结束了,但是“ps -a”的时候,子进程的进程信息还能打出来,可以看到后面带了一个单词,那就说明这个时候子进程已经结束了,但是它的资源没有被回收,子进程处于僵尸状态,进程已经结束,但资源没有被回收,但是尸体没烂,没有被大自然分解,这相当于父进程还在,子进程已经结束了,父进程如果不回收它的资源,那么子进程就是僵尸,如果父进程也结束了,父进程也没回收,那父子进程都挂了,系统就回收,但只要父进程还在,系统就不会回收子进程的资源。

5、修改程序的说明

再将程序稍微改一改,在 while 处添加 wait ,调一下 wait ,它会先等子进程结束了,回收子进程的资源,再运行父进程的 while循环,此程序一开始父进程就执行,然后先让它等,怎么等?

这个函数有一个参数是一个整型的指针,这个参数用来保存子进程的退出状态的,定义一个整形的变量传递指针进去,这个指针指向的整形变量就保存了子进程的退出状态。

 

三、wait 的相关内容

1、返回值

返回值是什么?如果执行成功,返回的是子进程的进程号,出错返回负一。

2、功能及其代码和说明

看此函数的功能,它详细的描述等待子进程终止,如果子进程终止了,则该函数回收它的资源,如果子进程没有终止就等,调用 wait 函数的进程会被挂起,即进入挂起状态,直到它的一个子进程退出或收到一个不能被忽视的信号才会被唤醒,父进程只要调了 wait ,父进程就开始等,一直停在那里,直到它有一个子进程退出了或者是收到一个信号了,它才不等了,如果等的时候,如果调用进程没有子进程,是等不到的,或者它的子进程已经结束了,然后该函数它就不会堵塞,直接立即返回,现在试一下,将代码进行稍微的修改,如下所示:

/********************************************************

*       Filename:  fork.c

*     Description:

*         Version:   1.0

*         Created:   2019年01月08日 01时43分00秒

*        Revision:   none\

*        Compiler:   gcc

*          Author:   YOUR NAME().

*         Company:

**********************************************************

#include <unistd.h>

#include <stdio.h>

int main(int argc, char *argv[])

{

pid_t pid;

pid_t pid_bk;

int i;

int s;

pid=fork();

if(pid<0)

{

perror(“fork”)

return 0;

}

else if(pid == 0)

{

//while(1)

for(i=0;i<5;i++)

{

printf(“this is son process\n”);

sleep(1);

}

}

else

{

pid_bk=wait(&s)

printf(“pid_bk=%d\n”,pid-bk”)

while(1)

{

printf(“this is father process\n”)

sleep(1)

}

}

用 s 保存子进程的退出状态,可以看到子进程是循环五次的,父进程当中调 wait ,传 s 的地址进来。接 wait 的返回值,如果 wait成功,它应该是子进程的进程号, s 里边保存着子进程的退出状态,如果不想保存子进程的退出状态。

可以看到子进程在“for(i=0;i<5;i++)

{

printf(“this is son process\n”);

sleep(1);

}”循环5秒,然后父进程就会“pid_bk=wait(&s)”再等五秒,等五秒钟到了之后,子进程结束了,然后它将状态保存在 S 里边,并且返回值给 pid_bk 赋值,即子进程的进程号,然后 wait 还会干一件事情,即回收子进程的资源,然后父进程再进入循环。

3、运行上述代码及说明

将以上代码运行,效果如下:

[01_day]./wait

this is son process

this is son process

this is son process

this is son process

this is son process

pid_bk=6815

this is father process

this is father process

this is father process

this is father process

this is father process

可以看到前五秒的时候只有子进程在打印,父进程在 wait ,五秒钟之后,拿到了子进程的进程号码,父进程就开始在运行 while (1)了。

4、ps -a代码及说明

这时再去 ps -a ,执行代码效果如下:

[~]ps -a

PID TTY      TIME CMD

6814 pts/0     00:00:00 wait

6817 pts/2     00:00:00 ps

会发现子进程看不见了,只有父进程在,因为在代码当中去 wait的时候, wait 几个功能,一个是等到了之后,它要回收子进程的资源,然后将子进程的退出状态保存 S 里边,并且返回子进程的记号,这是 wait 的功能, wait 通过上述例子改编,能看到wait的效果。

 

四、取出子进程的退出状态

1、分析

子进程的退出状态怎么拿到?可以通过 WIFEXITED(status) 和WEXITSTATUS(status) ,子进程退出状态保存在 S 里边,然后可以通过 S ,

通过 WIFEXITED(status) 和 WEXITSTATUS(status) ,通过 WIFEXITED(status) 传 S 进去,这个 WIFEXITED(status) 的意思是:如果子进程是正常终止的,那取出的字段为非零,就是整个表达式的结果不为零,什么是非正常终止?

如果收到信号,然后终止的话,即被别人杀掉了,这就是非正常终止,如果程序正常结束了,即Retire了,就是正常终止,如果是正常终止的。

2、代码修改

现在将以上代码加个判断,如下所示:

/********************************************************

*       Filename:  fork.c

*     Description:

*         Version:   1.0

*         Created:   2019年01月08日 01时43分00秒

*        Revision:   none\

*        Compiler:   gcc

*          Author:   YOUR NAME().

*         Company:

**********************************************************

#include <unistd.h>

#include <stdio.h>

int main(int argc, char *argv[])

{

pid_t pid;

pid_t pid_bk;

int i;

int s;pid=fork();

if(pid<0)

{

perror(“fork”)

return 0;

}

else if(pid == 0)

{

//while(1)

for(i=0;i<5;i++)

{

printf(“this is son process\n”);

sleep(1);

}

return 5

}

else

{

pid_bk=wait(&s)

if(WIFEXITED(s) != 0)

{

printf(“%d\n”,WEXITSTATUS(s));

}

printf(“pid_bk=%d\n”,pid-bk”)

while(1)

{

printf(“this is father process\n”)

sleep(1)

}

}

3、代码说明

在上文代码中如果它不等于零,即是正常结束的,如果正常结束,看一下子进程的返回值,子进程会执行 return 0 ,那在上文代码中return 5 ,结束了之后就可以拿到它的返回值,那么怎么拿到它的返回值?可以通过 WEXITSTATUS(status) ,它传 S 进去。

4、首次执行结果出错

将以上代码运行,结果如下:

[01_day]gcc wait.c -o wait

/tmp/cc4Gf6DO.o: In function `main’:

wait.c:(.text+0x83) : undefined reference to `WIFEXITED’

wait.c:(.text+0x83) : undefined reference to `WEXITSTATUS’

collect2 : 1d 返回 1

5、对代码进行修改

`WIFEXITED’这个不认识,那是因为什么?因为 wait 函数应该包含头文件,所以将以上代码修改为:

#include <unistd.h>

#include <stdio.h>

#include <sys/types.h>

#include <sys/wait.h>

int main(int argc, char *argv[])

{

pid_t pid;

pid_t pid_bk;

int i;

int s;

pid=fork();

if(pid<0)

{

return 0;

}

else if(pid == 0)

{

//while(1)

for(i=0;i<5;i++)

{

printf(“this is son process\n”);

sleep(1);

}

return 5

}

else

{

pid_bk=wait(&s)

if(WIFEXITED(s) != 0)

{

printf(“%d\n”,WEXITSTATUS(s));

}

printf(“pid_bk=%d\n”,pid-bk”)

while(1)

{

printf(“this is father process\n”)

sleep(1)

}

}

6、再次运行代码及说明

再将上述代码运行试一下效果,效果如下:

image.gif 

可以看到前五秒都是子进程,父进程等五秒,五秒钟到了之后,打了那个五,所以说这是 wait 的功能,即子进程的退出状态保存在 S里边,

然后可以通过特定的 WIFEXITED(status)和WEXITSTATUS(status) 判断资金是否是正常终止退出的、子进程的返回值是多少,到此为止 wait 讲的差不多了。

 

相关文章
|
3天前
sleep()和wait()的区别
(1)wait()是Object的方法,sleep()是Thread类的方法 (2)wait()会释放锁,sleep()不会释放锁 (3)wait()要在同步方法或者同步代码块中执行,sleep()没有限制 (4)wait()要调用notify()或notifyall()唤醒,sleep()自动唤醒
13 5
|
存储 缓存 安全
sleep () 和 wait () 的区别
sleep () 和 wait () 的区别
89 0
|
监控
Sleep()和wait()方法的区别
Sleep()和wait()方法的区别
136 0
|
Java 程序员
sleep 和 wait 的区别
Java 中,线程的 "sleep" 和 "wait" 方法区别
129 0
|
Linux
wait() 函数和 waitpid() 函数
wait() 函数和 waitpid() 函数
727 0
wait() 函数和 waitpid() 函数
|
物联网 Linux 开发者
signal 函数1|学习笔记
快速学习 signal 函数1
signal 函数1|学习笔记
|
监控
实践解读CLOSE_WAIT和TIME_WAIT
实践解读CLOSE_WAIT和TIME_WAIT
392 0
实践解读CLOSE_WAIT和TIME_WAIT
线程 - wait、await 区别
线程 - wait、await 区别
338 0