C程序不会从等待语句

时间:2015-07-21 06:47:05

标签: c wait execv

我必须将一个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
      {
         ...
      }
   }
}

是否需要做任何事情来告诉wait-command没有更多的子进程? 使用OpenVMS,程序运行正常。

非常感谢您的帮助

2 个答案:

答案 0 :(得分:2)

我建议不要在Linux上使用vfork,因为fork(2)足够有效,这要归功于Linux内核中的懒惰copy-on-write技术。

您应该检查fork的结果。除非它失败,否则会创建一个流程,wait(或waitpid(2),或许WNOHANG,如果您不想真正等待,但只是发现已经结束子进程...)不应该失败(即使子进程中的exec函数失败,fork也会成功)。

您也可能小心使用SIGCHLD信号,请参阅signal(7)。使用信号的防御方法是在信号处理程序中设置一些volatile sigatomic_t标志,并在循环内测试并清除这些标志。回想一下,只有异步信号安全函数(并且它们中很少有)可以在信号处理程序中间接调用。另请阅读POSIX signals

花些时间阅读Advanced Linux Programming,以便在您的脑海中获得更广阔的视野。不要尝试在POSIX上模仿OpenVMS,但要以POSIX或Linux的方式思考!

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

你可能想要编译所有警告&amp;调试信息(gcc -Wall -Wextra -g)然后使用gdb调试器。你也可以strace(1)你的程序(可能是-f

您可能想了解memory overcommitment。我不喜欢这个功能并且通常会禁用它(例如以root身份运行echo 0 > /proc/sys/vm/overcommit_memory)。另见proc(5) - 这对于了解...非常有用。

答案 1 :(得分:1)

来自man vfork

  

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

当致电exit()execv之后)失败时,您不得致电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之前和之后输入打印语句。