子进程未终止

时间:2017-04-27 07:59:06

标签: c fork wait

我有一个小实用程序需要使用fork()wait(),但是,我遇到的问题是在父程序运行后子进程没有被终止。知道如何解决它吗?

int test(void)
{
    pid_t PID;
    PID = fork();

    if (PID == 0) {

            sprintf(execmd, "/root/test);
            system(execmd);

            sprintf(filename, "test_results.txt);

            FILE *fp = fopen(filename, "r");

            fscanf (fp, "%s%s%s%s%s", &A, &B, &C, &D, &E);
            printf ("A=%s B=%s C=%s D=%s E=%s\n", A, B, C, D, E);


            fclose (fp);
    }
    else    // *** Parent Process *** 
    {
            int status;
            wait(&status);
    }

    return 0;
}

1 个答案:

答案 0 :(得分:0)

一开始:您的代码根本不应该编译,因为您没有关闭字符串:

sprintf(execmd, "/root/test);
system(execmd); //         ^ missing quote!

(顺便说一下,为什么不简单地拨打system("/root/test");?至少从显示的代码中,我看不出有什么理由需要副本......)

然后查看wait文档:

  

wait()函数应暂停执行调用线程,直到调用进程的一个已终止子进程的状态信息可用,或者直到传递其动作是执行信号捕获功能的信号或终止这个过程。如果等待终止相同进程的wait()或waitpid()中挂起了多个线程,则只有一个线程应在目标进程终止时返回进程状态。如果在调用wait()之前状态信息可用,则应立即返回。

     

返回值
  如果由于子进程的状态可用而返回wait()或waitpid(),则这些函数将返回一个值,该值等于报告其状态的子进程的进程ID。如果由于向调用进程发送信号而返回wait()或waitpid(),则返回-1并将errno设置为[EINTR]。如果在选项中设置WNOHANG时调用了waitpid(),则它至少有一个由pid指定的子进程,其状态不可用,并且状态不可用于pid指定的任何进程,返回0。否则,将返回(pid_t)-1,并设置errno以指示错误。

所以 - 如果等待返回,你首先要检查是否实际返回了进程ID,否则你可能重新进入等待状态。

然后,如果等待未返回,则您的子进程仍在运行。我不明白为什么你的进程因为文件处理而被阻止(好吧,你没有执行任何错误检查,但这是与你的问题无关的另一个问题),所以很可能你的子进程被捕获了致电system

您现在需要的是一种超时机制。我的主张现在如下:

  1. 为自触发事件创建管道
  2. 使用sigaction
  3. 为SIGCHLD安装信号处理程序
  4. 在信号处理程序中,执行等待并将单个字节写入管道
  5. 在您的主要功能中,您当前正在等待您的子进程,现在您的管道首先selectpoll超时。如果发生超时,请向您的子进程发送一个信号(您可以执行两次,首先发送SIGTERM以允许您的孩子正常终止,如果这没有帮助,请在之后发送SIGKILL
  6. 替代方案:如果在linux上,看看signalfd - 那么你就不可移动了,但是更容易完成相同的工作(选择/轮询你的fd并且成功时,你可以在主要调用wait再次发挥作用)。

    此外,我建议稍微重新构建您的程序:system将在内部再次调用forkexecve ,因此您实际上会创建另一个孩子过程

    所以我宁愿这样做:

    // preparations as described above
    
    if (PID == 0)
    {
        execl("/root/test", ""); // won't return unless on error!
        // some error handling?
        return -1;
    }
    
    // parent process
    if(PID < 0)
    {
        // error, the child process could not be created!
        return -1;
    }
    
    // select/poll
    if(timeout)
    {
        kill(PID, SIGTERM);
        // select/poll
        if(timeout)
            kill(PID, SIGKILL);
    }
    
    //***************************************************
    // if using signalfd:
        int status;
        wait(&status);
        // yet to be done: check return value, status, errno
        // you might need a loop...
    // otherwise, prefer doing this in the signal handler
    // however, the following out put MUST NOT be done there, as
    // file handling is not async safe!
    // just set some global flag there if the process terminated successfully!
    //***************************************************
    
    if(child_was_successful)
    {
        FILE* fp = fopen("test_results.txt", "r");
        if(fp) // only if successful!
        {
            // missing declarations (presumably global), adding them here:
            char A[32], B[32], C[32], D[32], E[32];
            // some fixes:
            // 1. checking return value
            // 2. arrays already decay to pointers when being passed
            //    -> you do not need to take the address of again!
            // 3. adding max length to your arrays prevents fscanf
            //    from writing beyond your array boundaries
            if(fscanf (fp, "%31s%31s%31s%31s%31s", A, B, C, D, E) == 5)
            //                                     ^ no ampersand!
            //               ^ 31: need to leave space for terminating 0 character            
            {
                printf ("A=%s B=%s C=%s D=%s E=%s\n", A, B, C, D, E);
            }
    
            fclose (fp);
        }
    }