waitpid() 问题。

fcuklife 2009-12-30 09:41:51
While( (pid = waitpid(-1, &stat, WNOHANG )) >0 )
WNOHNG, 它告诉 waipid在没有终止的子进程运行时不要堵塞;我们不能循环中调用wait, 因为没有办法防止 wait 在有未终止的子进程运行时阻塞; 这里的为啥wait 阻塞不能循环调用呢?
...全文
292 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
kingstarer 2009-12-30
  • 打赏
  • 举报
回复
呃 是我糊涂了 因为写过的waitpid都是等待指定进程的 都忘了可以不指定了
  • 打赏
  • 举报
回复
[Quote=引用楼主 fcuklife 的回复:]
While( (pid  = waitpid(-1, &stat, WNOHANG )) >0 )
WNOHNG, 它告诉 waipid在没有终止的子进程运行时不要堵塞;我们不能循环中调用wait, 因为没有办法防止 wait 在有未终止的子进程运行时阻塞;这里的为啥wait 阻塞不能循环调用呢?

[/Quote]

首先waitpid是可以设置非阻塞,而wait一般是阻塞的。
既然你的返回条件在while里,那么如果wait阻塞,while就不会循环,那就没有意义了,基本等于一个if.所以它不希望阻塞。

wait跟waitpid的区别,参考这里,建议看看APUE,毕竟是经典。
http://blog.chinaunix.net/u/21684/showart_425090.html

xianyuxiaoqiang 2009-12-30
  • 打赏
  • 举报
回复
“好读书,不求甚解。”看书的时候不用太计较个别一两句话。
“学而时习之,不亦悦乎?”别光看书,写点代码体会一下。
arong1234 2009-12-30
  • 打赏
  • 举报
回复
这不是一个规则,只是在他那个程序中不能阻塞,所以他使用了WNOHANG来避免阻塞。在可以阻塞的情况下当然可以循环调用(不过一般都是在主进程需要确保所有子进程都退出的情况下调用,很少有其他应用吧)
[Quote=引用楼主 fcuklife 的回复:]
While( (pid  = waitpid(-1, &stat, WNOHANG )) >0 )
WNOHNG, 它告诉 waipid在没有终止的子进程运行时不要堵塞;我们不能循环中调用wait, 因为没有办法防止 wait 在有未终止的子进程运行时阻塞;这里的为啥wait 阻塞不能循环调用呢?

[/Quote]
arong1234 2009-12-30
  • 打赏
  • 举报
回复
兄弟这么大段和人家问题什么关系啊?
[Quote=引用 1 楼 z569362161 的回复:]
waitpid使用实例

[/Quote]
z569362161 2009-12-30
  • 打赏
  • 举报
回复
waitpid使用实例

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
void die(const char *msg)
{
perror(msg);
exit(1);
}

void child2_do()
{
printf("In child2: execute 'date'\n");

sleep(5);
if (execlp("date", "date", NULL) < 0) {
perror("child2 execlp");
}
}

void child1_do(pid_t child2, char *argv)
{
pid_t pw;

do {
if (*argv == '1') {
pw = waitpid(child2, NULL, 0);
}
else {
pw = waitpid(child2, NULL, WNOHANG);
}
if (pw == 0) {
printf("In child1 process:\nThe child2 process has not exited!\n");
sleep(1);
}
}while (pw == 0);

if (pw == child2) {
printf("Get child2 %d.\n", pw);
sleep(5);
if (execlp("pwd", "pwd", NULL) < 0) {
perror("child1 execlp");
}
}
else {
printf("error occured!\n");
}
}

void father_do(pid_t child1, char *argv)
{
pid_t pw;

do {
if (*argv == '1') {
pw = waitpid(child1, NULL, 0);
}
else {
pw = waitpid(child1, NULL, WNOHANG);
}

if (pw == 0) {
printf("In father process:\nThe child1 process has not exited.\n");
sleep(1);
}
}while (pw == 0);

if (pw == child1) {
printf("Get child1 %d.\n", pw);
if (execlp("ls", "ls", "-l", NULL) < 0) {
perror("father execlp");
}
}
else {
printf("error occured!\n");
}
}

int main(int argc, char *argv[])
{
pid_t child1, child2;

if (argc < 3) {
printf("Usage: waitpid [0 1] [0 1]\n");
exit(1);
}

child1 = fork();

if (child1 < 0) {
die("child1 fork");
}
else if (child1 == 0) {
child2 = fork();

if (child2 < 0) {
die("child2 fork");
}
else if (child2 == 0) {
child2_do();
}
else {
child1_do(child2, argv[1]);
}
}
else {
father_do(child1, argv[2]);
}

return 0;
}


学习waitpid函数的使用,编写上述函数。主要功能是:利用fork创建子进程child1,子进程child1利用fork创建子进程child2。child2暂停5s,执行date命令,退出。child1等待child2的退出,然后暂停5s,执行pwd命令,退出。父进程等待child1的退出,然后执行ls -l命令,然后退出。采用父子进程的关系,保证了各进程执行的顺序,即执行child2->child1->father(child2是father的“孙”进程^_^)。

1、waitpid的调用格式

在这里,要用到一个小的知识点。那就是,在编写程序的过程中,可以先不写头文件,编写完成后,用gcc的-Wall参数来编译。如果一个函数没有相应的头文件,一般会提示:

waitpid.c:17: warning: implicit declaration of function `sleep'
waitpid.c:18: warning: implicit declaration of function `execlp'
waitpid.c: In function `main':
waitpid.c:90: warning: implicit declaration of function `fork'


其中,implicit declaration of function ""指函数“”声明不明确,也就是缺少声明。然后就可以利用man <N> function来查寻需要的头文件。一般地,N=3就可以查到。比如,

[armlinux@lqm waitpid]$ man 3 sleep


对于函数waitpid,应用:


NAME
wait, waitpid - wait for process termination

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

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options)


主要介绍options。

WNOHANG--若由pid指定的子进程不是立即可用,则waitpid不阻塞,此时返回值为0。

WUNTRACED--若实现某支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来没有报告过,就返回其状态。
0--阻塞父进程,等待子进程退出。
2、makefile和运行测试结果
CC = gcc
OBJS = waitpid
SRC = waitpid.c
CFLAGS = -Wall -g

$(OBJS): $(SRC)
$(CC) $(CFLAGS) $^ -o $@

clean:
rm -rf $(OBJS)
运行:
[armlinux@lqm waitpid]$ ./waitpid 1 1
In child2: execute 'date'
二 11月 7 17:03:16 CST 2006
Get child2 12779.
/home/armlinux/program/my_apue_practice/waitpid
Get child1 12778.
总用量 40
-rw-r--r-- 1 armlinux armlinux 125 11月 3 16:43 Makefile
-rwxrwxr-x 1 armlinux armlinux 32038 11月 7 16:57 waitpid
-rw-rw-r-- 1 armlinux armlinux 1705 11月 7 16:57 waitpid.c
[armlinux@lqm waitpid]$ ./waitpid 0 1
In child1 process:
The child2 process has not
In child2: execute 'date'
In child1 process:
The child2 process has not
In child1 process:
The child2 process has not
In child1 process:
The child2 process has not
In child1 process:
The child2 process has not
二 11月 7 17:03:36 CST 2006
Get child2 12782.
/home/armlinux/program/my_apue_practice/waitpid
Get child1 12781.
总用量 40
-rw-r--r-- 1 armlinux armlinux 125 11月 3 16:43 Makefile
-rwxrwxr-x 1 armlinux armlinux 32038 11月 7 16:57 waitpid
-rw-rw-r-- 1 armlinux armlinux 1705 11月 7 16:57 waitpid.c
将Makefile中的CC改为arm-linux-gcc,经过交叉编译,下载到target board上面,运行良好。
3、注意问题
1)exec族函数执行完成自动退出整个子程序,因此sleep(5)语句要放在其前面。另外,exec函数容易出错,必须要加入出错处理,只要perror就可以了。perror函数在输出字符串后自动加一个冒号,然后输出出错原因。
2)程序框架比较简单,还可以加入许多处理,进行扩充。
do_fork 2009-12-30
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 kingstarer 的回复:]
因为是阻塞调用,如果中间有一个子进程没有结束就会在那停住,一直等到子进程结束为止

即使后面的所有子进程都结束也也无法回收,要等待现在处理的子进程结束才行
[/Quote]

可以等待所有子进程返回,而不是指定回收其中某一个,
只要有任意子进程返回,waitxxx就能返回
kingstarer 2009-12-30
  • 打赏
  • 举报
回复
因为是阻塞调用,如果中间有一个子进程没有结束就会在那停住,一直等到子进程结束为止

即使后面的所有子进程都结束也也无法回收,要等待现在处理的子进程结束才行
do_fork 2009-12-30
  • 打赏
  • 举报
回复
谁说不能在循环中阻塞waitxxx呢?

假如你有多个子进程要回收,只能循环了
yangch_nhcmo 2009-12-30
  • 打赏
  • 举报
回复
wait()本来就阻塞了,用于while()没啥意义了
fcuklife 2009-12-30
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 arong1234 的回复:]
兄弟这么大段和人家问题什么关系啊?
引用 1 楼 z569362161 的回复:
waitpid使用实例



对哦。楼上答得不切题哦。

如果我将你的用例用中的 waitpid全换成了 wait 会有啥结果?
[/Quote]


对哦。楼上答得不切题哦。

如果我将你的用例用中的 waitpid全换成了 wait 会有啥结果?

69,368

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧