1

waitpid如果我execl在可能需要时间完成的子进程中使用,我什么时候需要使用?

当我waitpid在父级中使用时,它告诉我子级正在运行,因为 from 的返回值为waitpid0。但是,如果我waitpid在一段时间后在另一个函数中调用,它会返回 -1 并errno设置为ECHILDwaitpid如果我不确定孩子是否完成了,我应该什么时候使用?

//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") ;
}
4

3 回答 3

6

如果忽略信号 SIGCHLD(这是默认值)并且您跳过 Jonathan 提到的 WNOHANG,则 waitpid 将挂起,直到子退出,然后失败并显示代码 ECHILD。我自己在父进程应该等待子进程完成并且为 SIGCHLD 注册处理程序似乎有点矫枉过正的场景中遇到了这个问题。自然的后续问题将是“在这种情况下可以将 ECHILD 视为预期事件,还是我总是应该为 SIGCHLD 编写处理程序?”,但对此我没有答案。

waitpid(2) 的文档中

孩子

(for waitpid() or waitid()) 由pid (waitpid()) 或idtype 和id (waitid()) 指定的进程不存在或者不是调用进程的子进程。(如果 SIGCHLD 的操作设置为 SIG_IGN,这可能发生在自己的孩子身上。另请参阅有关线程的 Linux 注释部分。)

再往下

POSIX.1-2001 指定如果 SIGCHLD 的处置设置为 SIG_IGN 或为 SIGCHLD 设置了 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 没有被忽略一样,也就是说,

另请参阅此答案

于 2014-07-06T19:44:31.533 回答
2

如果您等待WNOHANG,那么除非您的孩子已经死了,否则您将不会获得任何有用的状态-甚至可能还没有开始(当父母执行时,它可能仍在等待从磁盘加载可执行文件waitpid()) .

如果您想知道孩子已经完成,请不要使用WNOHANG0用于第三个参数,除非您想了解未跟踪或继续的过程。这将等到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 没有那个),但我不要期望在其他地方得到不同的结果。

于 2014-03-27T14:05:42.320 回答
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;
            }        

        }            
}
于 2014-03-28T13:24:46.300 回答