【发布时间】:2021-05-18 16:40:32
【问题描述】:
我有一个 c 程序来创建一个 TCP 套接字并在无限循环中继续等待连接。每次客户端连接到程序时,我都会生成一个新的子进程来处理客户端请求。我的程序只能在信号中断时退出(例如ctrl+c)。
我不希望父进程挂在那里等待一个孩子,我希望他们可以同时工作。 父进程在fork之后应该做的是检查是否有子进程完成,如果是,则清理它们。
目前我的做法是(这里没有错误检查以节省空间,我的真实代码中有很多错误检查):
if (fork()==0){
/* Child process. */
}
else{
close(client); /* <- Cut down the connection from parent with the client. */
waitpid(0, &status_exit, WNOHANG|WUNTRACED);
child_spawn++; /* One parent int variable to count total number of child process. */
}
但这引发了另一个问题,因为父进程总是挂起并等待连接,可能总是有一两个先前完成的子进程无法清理,直到父进程可以分叉另一个并清理它们。
即使我的程序在退出前收到信号中断后可以清理每个僵尸,但我希望它自己清理每个完成的孩子。
请帮帮我,谢谢。如果我有任何不明白的地方,请发表评论以便我解释。
【问题讨论】:
-
由于您使用的是
WNOHANG,您可以在waitpid上循环,而它的返回值不是0(不再是死子)而不是-1(错误)。循环wait实际上是管理多个进程时使用的正确方法。 -
这是一个如何等待要么 I/O事件或子进程终止的一般问题的实例,以先到者为准; Unix 从来没有让这变得简单或整洁。我所知道的最简洁的处理方法是使用 Linux 特定的
signalfd接口。一种不太整洁但更便携的方式使用专用于调用waitpid的线程。还有一个更丑陋的方法,它至少可以避免线程和特定于操作系统的 POSIX 扩展,它是使用pselect和SIGCHLD处理程序。您可以接受这些选项吗? -
@Jean-BaptisteYunès 谢谢这是个好主意。但是由于父进程会一直等待连接,因此此时完成的任何子进程都将成为僵尸进程,并且在父进程继续之前无法清理。
-
@zwol 我目前正在使用
waitpid(0, &status_exit, WNOHANG|WUNTRACED);在父进程产生子进程以检查是否有任何未清理的已完成进程。 -
@Rrobinvip 你无法避免僵尸......但是,你可以使用
SIGCHLD捕捉死亡并在捕捉函数中循环waitpid。