没有抽到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()
一次。因此,您使用的所有那些WIFEXITED
和WEXITSTATUS
宏正在处理的初始调用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
并不需要是全球性的,因为它从来没有访问其他地方)。