没有抽到waitpid函数()返回正确WEXITSTATUS错误条件

没有抽到waitpid函数()返回正确WEXITSTATUS错误条件

问题描述:

我有一个命令和一些输入,当在命令行中运行会返回一个错误,与1相关的错误代码:没有抽到waitpid函数()返回正确WEXITSTATUS错误条件

$ foo bar 
[some useful error message...] 
$ echo $? 
1 

我想抓住这个错误代码waitpid()

... 
char *proc_cmd = "foo bar" 
pid_t proc = popen4(proc_cmd, in_fd, out_fd, err_fd, POPEN4_FLAG_NONE); 
... 
if (waitpid(proc, &global_foo_status, WNOHANG | WUNTRACED) == -1) { 
    /* process failed */ 
} 
... 
pthread_create(&proc_thread, NULL, perform_foo_function, bar_data); 
pthread_join(proc_thread, (void **) NULL); 
... 

我的线程将运行perform_foo_function()直到有没有更多的bar_data处理,或直到进程失败,因为在数据中的错误:

static void * perform_foo_function (data *bar_data) { 
    /* check before */ 
    if (WIFEXITED(global_foo_status)) { 
     int exit_status = WEXITSTATUS(global_foo_status); 
     if (exit_status != 0) 
      /* process failed */ 
    } 

    /* do stuff with bar_data */ 
    while (bar_data) { 
     /* causes error ... */ 
    } 

    /* check after */ 
    if (WIFEXITED(global_foo_status)) { 
     int exit_status = WEXITSTATUS(global_foo_status); 
     if (exit_status != 0) 
      /* process failed */ 
    } 

    pthread_exit(NULL); 
} 

我的问题是如何捕捉这个过程的错误状态?在调试过程中,WEXITSTATUS始终为零,无论我是故意创建错误情况还是提供合法输入。

我对waitpid()和相关的状态码检查有什么误解,以及我应该做些什么才能使其发挥作用?

后续

下面的代码似乎工作,而不会阻塞:

... 
char *proc_cmd = "foo bar" 
pid_t global_foo_pid = popen4(proc_cmd, in_fd, out_fd, err_fd, POPEN4_FLAG_NONE); 
... 
if (waitpid(global_foo_pid, &global_foo_status, WNOHANG | WUNTRACED) == -1) { 
    /* process failed */ 
} 
... 
pthread_create(&proc_thread, NULL, perform_foo_function, bar_data); 
pthread_join(proc_thread, (void **) NULL); 
... 

static void * perform_foo_function (data *bar_data) 
{ 
    /* do stuff with bar_data */ 
    while (bar_data) { 
     /* causes error ... */ 
    } 

    /* check after */ 
    if (WIFEXITED(global_foo_status)) { 
     waitpid(global_foo_pid, &global_foo_status, WUNTRACED); 
     int exit_status = WEXITSTATUS(global_foo_status); 
     if (exit_status != 0) 
      /* process failed */ 
    } 

    pthread_exit(NULL); 
} 

我猜的是“检查后,” waitpid()电话不挂,因为该工艺具有已经退出这一步。

这里有一些东西。

首先,您的global_foo_status变量会在您致电waitpid()或朋友之后(并且仅在此之后)更新。在提供的代码中,您只能在创建线程之前调用waitpid()一次。因此,您使用的所有那些WIFEXITEDWEXITSTATUS宏正在处理的初始调用waitpid()global_foo_status的值相同。这几乎可以肯定你为什么在调试时总是看到零值,因为你的进程终止后你永远不会获得更新的值,而且你只是反复检查初始值。如果您想检查流程是否已退出,则必须每次再次致电waitpid()

其次,WIFEXITED的计算结果为true,如果进程正常终止,但这不是进程可以终止的唯一方式。还有另一个宏,WIFSIGNALED,如果由于接收到信号而终止进程,则该宏将被评估为真。如果您只使用WIFEXITED来检查终止,并且您的进程被信号异常终止,那么您将永远无法检查。更好的办法是使用waitpid()的返回来确定进程是否因任何原因而死亡。

你的功能或许应该看起来更像是这样的:

static void * perform_foo_function (data *bar_data) { 

    /* check before */ 

    pid_t status = waitpid(global_foo_pid, &global_foo_status, WNOHANG); 
    if (status == -1) { 
     perror("error calling waitpid()"); 
     exit(EXIT_FAILURE); 
    } 
    else if (status == global_foo_pid) { 

     /* Process terminated */ 

     if (WIFEXITED(global_foo_status)) { 

      /* Process terminated normally */ 

      int exit_status = WEXITSTATUS(global_foo_status); 
      if (exit_status) { 
       /* Process failed */ 

       return NULL; 
      } 
      else { 
       /* Process terminated normally and successfully */ 

       return NULL; 
      } 
     } 
     else { 

      /* Process terminated abnormally */ 

       return NULL; 
     } 
    } 

    /* Process is still running if we got here */ 

    /* do stuff with bar_data */ 

    while (bar_data) { 
     /* causes error ... */ 
    } 

    /* Check after - if getting an error from doing stuff 
     with bar_data implies the process should always 
     shortly terminate, then you probably don't want 
     WNOHANG in the following line.      */ 

    status = waitpid(global_foo_pid, &global_foo_status, WNOHANG); 
    if (status == -1) { 
     perror("error calling waitpid()"); 
     exit(EXIT_FAILURE); 
    } 
    else if (status == global_foo_pid) { 

     /* Process terminated */ 

     if (WIFEXITED(global_foo_status)) { 

      /* Process terminated normally */ 

      int exit_status = WEXITSTATUS(global_foo_status); 
      if (exit_status) { 
       /* Process failed */ 

       return NULL; 
      } 
      else { 
       /* Process terminated normally and successfully */ 

       return NULL; 
      } 
     } 
     else { 
      /* Process terminated abnormally */ 

       return NULL; 
     } 
    } 

    pthread_exit(NULL); 
} 

这整个过程检查是对分解出到一个单独的功能的总理候选人,太。

如果您有多个线程同时运行perform_foo_function(),那么waitpid()只会在其中一个线程中正确返回。您可能需要一个单独的变量,global_foo_has_finished或类似,该线程可以试图调用waitpid()前检查。您还会希望同步访问所有这些全局,或重新设计所以他们没有必要的(你可以通过global_foo_pid到您的权利线程功能,比如,和global_foo_status并不需要是全球性的,因为它从来没有访问其他地方)。