用于子级的execl的waitpid在ECHILD中返回-1?

时间:2014-03-27 07:36:37

标签: c linux fork waitpid os.execl

如果我使用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") ;
}

3 个答案:

答案 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;
            }        

        }            
}