【问题标题】:Child process is not terminated子进程未终止
【发布时间】:2023-03-07 20:01:02
【问题描述】:

我有一个需要使用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;
}

【问题讨论】:

标签: c fork wait


【解决方案1】:

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

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 为 SIGCHLD 安装信号处理程序
  3. 在信号处理程序中,等待并将单个字节写入您的管道
  4. 在您当前等待子进程的主函数中,您现在将首先使用selectpoll 为您的管道设置超时。如果发生超时,向您的子进程发送一个信号(您可以这样做两次,首先发送SIGTERM 让您的孩子优雅地终止,如果这没有帮助,然后发送SIGKILL

替代方案:如果在 linux 上,请查看signalfd - 那时您不是可移植的,但可以更轻松地完成相同的工作(为您的 fd 选择/轮询,如果成功,您可以再次在 main 函数中调用 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);
    }
}

【讨论】:

    猜你喜欢
    • 2011-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    相关资源
    最近更新 更多