我有一个小实用程序需要使用fork()
和wait()
,但是,我遇到的问题是在父程序运行后子进程没有被终止。知道如何解决它吗?
int test(void)
{
pid_t PID;
PID = fork();
if (PID == 0) {
sprintf(execmd, "/root/test);
system(execmd);
sprintf(filename, "test_results.txt);
FILE *fp = fopen(filename, "r");
fscanf (fp, "%s%s%s%s%s", &A, &B, &C, &D, &E);
printf ("A=%s B=%s C=%s D=%s E=%s\n", A, B, C, D, E);
fclose (fp);
}
else // *** Parent Process ***
{
int status;
wait(&status);
}
return 0;
}
答案 0 :(得分:0)
一开始:您的代码根本不应该编译,因为您没有关闭字符串:
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
select
或poll
超时。如果发生超时,请向您的子进程发送一个信号(您可以执行两次,首先发送SIGTERM
以允许您的孩子正常终止,如果这没有帮助,请在之后发送SIGKILL
。替代方案:如果在linux上,看看signalfd
- 那么你就不可移动了,但是更容易完成相同的工作(选择/轮询你的fd并且成功时,你可以在主要调用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);
}
}