我有一个命令和一些输入,当在命令行上运行时将返回错误,相关的错误代码为1:
$ 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()
来电不会挂起,因为此流程已在此步骤中退出。
答案 0 :(得分:1)
这里有几件事。
首先,您的global_foo_status
变量将在致电waitpid()
或朋友之后,之后才会更新。在提供的代码中,您只需在创建线程之前调用waitpid()
一次。因此,您使用的所有WIFEXITED
和WEXITSTATUS
宏都处理与global_foo_status
初始调用相同的waitpid()
值。这几乎可以肯定,当您进行调试时,您总是会看到零值,因为在您的流程终止后,您永远不会获得更新的值,并且您只是反复检查该初始值。如果您想检查流程是否已退出,则每次都必须再次致电waitpid()
。
其次,如果进程正常终止,WIFEXITED
的计算结果为true,但这不是进程终止的唯一方法。还有另一个宏WIFSIGNALED
,如果由于收到信号而终止进程,则会将其评估为true。如果您仅使用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
不会#39; t需要是全球性的,因为它从未在其他任何地方访问过。)