3

我必须将 C 程序从 OpenVMS 迁移到 Linux,并且现在在生成子进程的程序方面遇到了困难。生成了一个子进程(fork 工作正常),但 execve 失败(这是正确的,因为给出了错误的程序名称)。

但是为了重置活动子进程的数量,我随后调用了一个不返回的 wait()。当我通过 ps 查看进程时,我看到没有更多的子进程,但是 wait() 并没有像我想象的那样返回 ECHILD。

while (jobs_to_be_done)
{
   if (running_process_cnt < max_process_cnt)
   {
      if ((pid = vfork()) == 0)
      {
         params[0] = param1 ;
         params[1] = NULL ;
         if ((cstatus = execv(command, params)) == -1)
         {
            perror("Child - Exec failed") ;   // this happens
            exit(EXIT_FAILURE) ;
         }
      }
      else if (pid < 0)
      {
         printf("\nMain - Child process failed") ;
      }
      else
      {
         running_process_cnt++ ;
      }
   }
   else   // no more free process slot, wait
   {
      if ((pid = wait(&cstatus)) == -1)   // does not return from this statement
      {
         if (errno != ECHILD)
         {
            perror("Main: Wait failed") ;
         }
         anz_sub = 0 ;
      }
      else
      {
         ...
      }
   }
}

是否必须做任何事情来告诉等待命令没有更多的子进程?使用 OpenVMS,该程序可以正常工作。

非常感谢您的帮助

4

2 回答 2

2

我不建议vfork在 Linux 上使用这些天,因为fork(2)足够高效,这要归功于 Linux 内核中的惰性写入时复制技术。

您应该检查fork. 除非它失败,否则已经创建了一个进程,并且wait(或waitpid(2)WNOHANG如果你不想真正等待,但只是找出已经结束的子进程......)不应该失败(即使孩子中的exec功能失败了,叉子确实成功了)。

您也可以小心使用SIGCHLD信号,请参阅signal(7)。使用信号的一种防御方式是volatile sigatomic_t在信号处理程序中设置一些标志,并在循环中测试和清除这些标志。回想一下,只有异步信号安全函数(而且数量很少)可以在信号处理程序中被调用——甚至是间接调用。另请阅读有关POSIX 信号的信息。

花点时间阅读Advanced Linux Programming以获得更广阔的视野。不要试图在 POSIX 上模仿 OpenVMS,而是以 POSIX 或 Linux 的方式思考!

您可能希望始终waitpid在您的循环中,也许(有时或总是)使用WNOHANG. 因此waitpid,不应仅在您的 else 部分中调用,而应if (running_process_cnt < max_process_cnt)在循环的每次迭代中调用。

您可能希望使用所有警告和调试信息 ( gcc -Wall -Wextra -g) 进行编译,然后使用gdb调试器。您还可以strace(1)您的程序(可能使用-f

您可能想了解内存过度使用。我不喜欢这个功能并且通常禁用它(例如通过echo 0 > /proc/sys/vm/overcommit_memory以 root 身份运行)。另请参阅proc(5) - 这对了解...非常有用

于 2015-07-21T06:56:11.200 回答
1

来自man vfork

子进程不能从当前函数返回或调用exit(3),但可以调用_exit(2)

exit()当调用execv(after ) 失败时,您不得调用vfork- 您必须_exit()改用。很可能仅此一项就导致您看到wait不返回的问题。

我建议你使用fork而不是vfork. 使用起来更容易、更安全。

如果仅此一项还不能解决问题,则需要进行一些调试或减少代码,直到找到原因为止。例如以下应该运行而不挂起:

#include <sys/wait.h>

int main(int argc, char ** argv)
{
    pid_t pid;
    int cstatus;
    pid = wait(&cstatus);
    return 0;
}

如果您可以验证该程序没有挂起,那么一定是您的程序的某个方面导致了挂起。我建议在调用wait.

于 2015-07-21T07:52:20.327 回答