我在cpp写了一个shell,我希望得到一些建议。我有一个将在后台执行exec的命令,并且我试图跟踪哪些后台进程仍在运行。我想也许我可以跟踪PID并在/ proc /上执行字符串查找,但它似乎比它应该保持更长时间。我是通过使用sleep命令对它进行测试的,但它看起来总是留在我应该看完的任何地方。我可能只是没做正确的事情,看它是否还在运行。
提前感谢您的帮助。
答案 0 :(得分:0)
假设您通过fork()
或forkpty()
产生子进程,跟踪子进程的条件的一个合理的好方法是让父进程创建一个连接套接字 - 在分叉之前配对(例如通过socketpair()
),并让子进程调用dup2()
以使该套接字对的一端为stdin / stdout / stderr文件描述符,例如:
// Note: error-checking has been removed for clarity
int temp[2];
(void) socketpair(AF_UNIX, SOCK_STREAM, 0, temp);
pid_t pid = fork();
if (pid == 0)
{
// We are the child process!
(void) dup2(temp[1], STDIN_FILENO);
(void) dup2(temp[1], STDOUT_FILENO);
(void) dup2(temp[1], STDERR_FILENO);
// call exec() here...
}
这样做的好处是,现在父进程有一个文件描述符(temp[0]
),它连接到子进程的stdin
,stdout
和stderr
进程,父进程可以select()
在该描述符上查找子进程何时向其stderr
或stdout
流写入文本,然后可以read()
用于查找子进程写入内容的文件描述符(如果您希望将该文本显示给用户,则有用,或者如果不是,则可以将读取的文本丢弃),最重要的是,它将知道子进程何时关闭其stderr
和stdout
个流,因为父进程在该文件描述符上对read()
的下一次调用将指示0也称为EOF。
由于操作系统会在出于任何原因(包括崩溃)退出时自动关闭子进程的流,这是一种非常可靠的方式来通知子进程已经消失。
唯一可能的问题是子进程可以(无论出于何种原因)手动调用close(STDOUT_FILENO)
和close(STDERR_FILENO)
,但仍然保持运行状态;在这种情况下,父进程会像往常一样看到套接字对连接关闭,并且错误地认为子进程已经消失,而事实上它并没有。幸运的是,对于一个程序来说,这是非常罕见的,所以除非你需要超级健壮,否则你可以忽略那个极端情况。
答案 1 :(得分:0)
在类似POSIX的系统上,使用fork
创建任何子进程后,应通过从父进程调用wait
or waitpid
来清理这些子进程。使用名称“wait”是因为函数最常用于父项在子项退出或被终止之前无需执行的操作,但也可以使用waitpid
(通过传递WNOHANG
)来检查关于子进程是否完成而不使父进程等待。
请注意,至少在Linux上,当子进程已退出或被杀死但父进程尚未“等待”该子进程时,内核会将有关子进程的一些信息保存在内存中,作为“僵尸进程” 。这样做是为了稍后“等待”可以正确地获取有关孩子的退出代码或致命信号的信息。这些僵尸进程确实在/proc
中有条目,这可能就是为什么你看到一个孩子“停留的时间超过它应该”,如果这是你的检查方式。