如果我使用execl,我什么时候需要使用waitpid,这可能需要一段时间才能完成?
当我在父母中使用waitpid时,它正在给我的孩子运行,因为来自waitpid的返回值为0.我试图在一段时间之后在另一个函数中使用waitpid,在那里它使用ECHILD返回-1。如果我不确定天气孩子是否完成,我应该何时使用waitpid?
//pid_t Checksum_pid = fork();
Checksum_pid = fork();
if (Checksum_pid == 0)
{
execl(path, name, argument as needed, ,NULL);
exit(EXIT_SUCCESS);
}
else if (Checksum_pid > 0)
{
pid_t returnValue = waitpid(Checksum_pid, &childStatus, WNOHANG);
if ( returnValue > 0)
{
if (WIFEXITED(childStatus))
{
printf("Exit Code: _ WEXITSTATUS(childStatus)") ;
}
}
else if ( returnValue == 0)
{
//Send positive response with routine status running (0x03)
printf("Child process still running") ;
}
else
{
if ( errno == ECHILD )
{
printf(" Error ECHILD!!") ;
}
else if ( errno == EINTR )
{
// other real errors handled here.
printf(" Error EINTR!!") ;
}
else
{
printf("Error EINVAL!!") ;
}
}
}
else
{
/* Fork failed. */
printf("Fork Failed") ;
}
答案 0 :(得分:4)
如果信号SIGCHLD被忽略(这是默认值)并且您跳过Jonathan提到的WNOHANG,则waitpid将挂起,直到子项退出,然后使用代码ECHILD失败。我自己在父进程应该等待子进程完成的情况下遇到这种情况,为SIGCHLD注册处理程序似乎有点过分。自然的后续问题是"在这种情况下将ECHILD视为预期事件是否可以,或者我总是应该为SIGCHLD编写处理程序?", 但为此,我没有答案。
来自documentation for waitpid(2):
ECHILD
(对于waitpid()或waitid())由pid指定的进程(waitpid()) 或idtype和id(waitid())不存在或不是 呼叫过程。 (如果行动,这可能发生在自己的孩子身上 SIGCHLD设置为SIG_IGN。另请参阅Linux Notes部分 螺纹。)
并进一步向下
POSIX.1-2001指定如果SIGCHLD的处置设置为 为SIGCHLD设置SIG_IGN或SA_NOCLDWAIT标志(参见 sigaction(2)),然后终止的孩子不会成为僵尸和 对wait()或waitpid()的调用将阻塞,直到所有孩子都有 终止,然后将errno设置为ECHILD而失败。 (原本的 POSIX标准保留了将SIGCHLD设置为SIG_IGN的行为 不确定的。请注意,即使是SIGCHLD的默认处置 是"忽略",明确地将处置设置为SIG_IGN结果 对僵尸进程孩子的不同处理。)Linux 2.6符合 这个规范。但是,Linux 2.4(及更早版本)不会:如果是 当SIGCHLD被忽略时,调用wait()或waitpid() 调用行为就像SIGCHLD没有被忽略一样,也就是说, 调用阻塞,直到下一个子句终止,然后返回 进程ID和该子进程的状态。
另见this answer。
答案 1 :(得分:2)
如果您等待WNOHANG
,那么除非您的孩子已经死亡,否则您将无法获得任何有用的状态 - 它甚至可能还没有结束(它仍然可能正在等待加载可执行文件当父进程执行waitpid()
时)从磁盘。
如果您想知道孩子已经完成,请不要使用WNOHANG
- 使用0
作为第三个参数,除非您想了解未经处理或继续进程。这将等到Checksum_pid
确定的进程退出,或者系统通过一些神秘的方式(我从未见过这种方式)失去对它的追踪。
此代码生成Exit Code: 0
作为输出:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t Checksum_pid = fork();
if (Checksum_pid < 0)
printf("Fork Failed\n");
else if (Checksum_pid == 0)
{
execl("/bin/sleep", "/bin/sleep", "2", NULL);
exit(EXIT_FAILURE);
}
else
{
int childStatus;
pid_t returnValue = waitpid(Checksum_pid, &childStatus, 0);
if (returnValue > 0)
{
if (WIFEXITED(childStatus))
printf("Exit Code: %d\n", WEXITSTATUS(childStatus));
else
printf("Exit Status: 0x%.4X\n", childStatus);
}
else if (returnValue == 0)
printf("Child process still running\n");
else
{
if (errno == ECHILD)
printf(" Error ECHILD!!\n");
else if (errno == EINTR)
printf(" Error EINTR!!\n");
else
printf("Error EINVAL!!\n");
}
}
return 0;
}
它与您的代码非常相似;我只是将fork()
的支票移到了顶部。我仍然宁愿摆脱if
陈述的“浓密树木”,但这并不重要。运行此代码会发生什么?您需要更改什么才能收到ECHILD
错误(您可以更改它以便收到ECHILD
错误)吗?
当你设法获得基于此的代码来重现问题时,我们可以弄清楚你为什么会这样做。
使用GCC 4.8.2测试Mac OS X 10.9.2 Mavericks,使用GCC 4.8.1测试Ubuntu 13.10(我需要添加-D_XOPEN_SOURCE=700
以使用严格的编译标记进行编译; Mac OS X管理没有那个),但我不希望在其他地方得到不同的结果。
答案 2 :(得分:0)
int start(int Area)
{
int childStatus;
pid_t Checksum_pid = fork();
if(Checksum_pid < 0)
{
/* Fork failed. */
printf(" Fork Failed") ;
}
else if (Checksum_pid == 0)
{
for (int i = 0; i<5; i++)
{
if ( g_area[i] == Area)
{
execl(ScriptPath, ScriptName, NULL);
}
}
exit(EXIT_FAILURE);
}
else
{
/* This is the parent process. */
pid_t returnValue = waitpid(Checksum_pid, &childStatus, 0);
if ( returnValue > 0)
{
// Check if child ended normally
printf("WAITPID Successful") ;
if (WIFEXITED(childStatus))
{
printf("Exit Code: _ WEXITSTATUS(childStatus)");
}
}
else if ( returnValue == 0)
{
printf("Child process still running") ;
}
else
{
if ( errno == ECHILD )
{
printf("Error ECHILD!!") ;
}
else if ( errno == EINTR )
{
printf("Error EINTR!!") ;
}
else
{
printf(" Error EINVAL!!") ;
}
retCode = FAILED;
}
}
}