一开始:你的代码根本不应该编译,因为你没有关闭你的字符串:
sprintf(execmd, "/root/test);
system(execmd); // ^ missing quote!
(顺便说一句,你为什么不直接打电话给system("/root/test");?至少从显示的代码来看,我看不出有什么理由需要你复制一份……)
然后查看wait文档:
wait() 函数应暂停调用线程的执行,直到调用进程的已终止子进程之一的状态信息可用,或者直到传递一个信号,其动作是执行信号捕获函数或终止进程。如果有多个线程在 wait() 或 waitpid() 中挂起等待同一进程终止,则只有一个线程应返回目标进程终止时的进程状态。如果在调用 wait() 之前状态信息可用,则应立即返回。
返回值
如果 wait() 或 waitpid() 因为子进程的状态可用而返回,这些函数将返回一个等于报告状态的子进程的进程 ID 的值。如果 wait() 或 waitpid() 由于向调用进程传递信号而返回,则应返回 -1 并将 errno 设置为 [EINTR]。如果在选项中设置了 WNOHANG 调用了 waitpid(),它至少有一个由 pid 指定的状态不可用的子进程,并且状态对于 pid 指定的任何进程都不可用,返回 0。否则返回(pid_t)-1,设置errno表示错误。
所以 - 如果等待返回,您首先应该检查进程 ID 是否实际返回,否则您可能重新进入等待。
然后,如果等待没有返回,您的子进程仍在运行。我不明白为什么你的进程应该因为文件处理而被阻止(好吧,你没有执行任何错误检查,但这是与你的问题无关的另一件事),所以很可能你的子进程被捕获在致电system。
您现在需要的是一个超时机制。我现在的提议如下:
- 为自触发事件创建管道
- 使用
sigaction 为 SIGCHLD 安装信号处理程序
- 在信号处理程序中,等待并将单个字节写入您的管道
- 在您当前等待子进程的主函数中,您现在将首先使用
select 或poll 为您的管道设置超时。如果发生超时,向您的子进程发送一个信号(您可以这样做两次,首先发送SIGTERM 让您的孩子优雅地终止,如果这没有帮助,然后发送SIGKILL。
替代方案:如果在 linux 上,请查看signalfd - 那时您不是可移植的,但可以更轻松地完成相同的工作(为您的 fd 选择/轮询,如果成功,您可以再次在 main 函数中调用 wait )。
另外,我建议稍微重新构建您的程序:system 将在内部调用fork 和execve再次,因此您实际上创建了另一个子进程。
所以我宁愿这样做:
// preparations as described above
if (PID == 0)
{
execl("/root/test", ""); // won't return unless on error!
// some error handling?
return -1;
}
// parent process
if(PID < 0)
{
// error, the child process could not be created!
return -1;
}
// select/poll
if(timeout)
{
kill(PID, SIGTERM);
// select/poll
if(timeout)
kill(PID, SIGKILL);
}
//***************************************************
// if using signalfd:
int status;
wait(&status);
// yet to be done: check return value, status, errno
// you might need a loop...
// otherwise, prefer doing this in the signal handler
// however, the following out put MUST NOT be done there, as
// file handling is not async safe!
// just set some global flag there if the process terminated successfully!
//***************************************************
if(child_was_successful)
{
FILE* fp = fopen("test_results.txt", "r");
if(fp) // only if successful!
{
// missing declarations (presumably global), adding them here:
char A[32], B[32], C[32], D[32], E[32];
// some fixes:
// 1. checking return value
// 2. arrays already decay to pointers when being passed
// -> you do not need to take the address of again!
// 3. adding max length to your arrays prevents fscanf
// from writing beyond your array boundaries
if(fscanf (fp, "%31s%31s%31s%31s%31s", A, B, C, D, E) == 5)
// ^ no ampersand!
// ^ 31: need to leave space for terminating 0 character
{
printf ("A=%s B=%s C=%s D=%s E=%s\n", A, B, C, D, E);
}
fclose (fp);
}
}