for FORK
pid_t pid = fork();
1. fork 函数返回两次, >0 表示父进程,返回值为子进程ID; =0 表示子进程。
if( ( pid = fork() ) < 0 ){
//error
}
else if( pid == 0 ){
//child
}
else{
//parent
}
2. 父进程必须要回收子进程,这时必须用wait/waitpid。不然当子进程结束后,
它会变成僵死进程。用 "ps -ef" 命令查看,可看到起状态为<defunct>。
所所以,在fork()之后,我们一般是执行:
waitpid( pid, NULL, 0 );
参数1: pid表示到等待的子进程ID
参数2: NULL表示对子进程的结束状态不在意。
参数3: 控制选项
if( ( pid = fork() ) < 0 ){
//error
}
else if( pid == 0 ){
//child
...
}
else{
waitpid( pid, NULL, 0 ); //用于等待子进程结束.
}
3. 问题提出
在调用waitpid后,父进程被阻塞,将不能执行其他的任务,这在监听程序中是
不允许的。所以,必须要能回收掉子进程,并且能不被阻塞,要解决这个问题,
我们可以fork两次,让子进程被init进程托管。

if( ( pid = fork() ) < 0 ){
//error
}
else if( pid == 0 ){
//first child exit !
if( fork() > 0 ){
exit(0);
}
else{
//second child...
}
}
else{
waitpid( pid, NULL, 0 );
//因为第一个子进程马上退出,所以waitpid在等到其结束时马上返回,第二
//个子进程将被init进程托管!
}
4. 问题提升
我们让子进程被init进程托管,也就等于对它放弃了控制权,没办法知道它什么时
候结束的,以及结束的状态是什么。所以,为了父进程不被阻塞,并且能够及时的
回收掉子进程。这时,用信号是一个不错的选择。

int chld_count = 0;
void sigchd_exit(int signo)
{
if( waitpid(-1, NULL, WNOHANG) > 0 ) chld_count--;
printf( "child count: %d\n", chld_count );
}
void set_sigchd()
{
signal(SIGCHLD, sigchd_exit); //子程序退出的信号
signal(SIGINT, sigchd_exit); //Ctrl+C
signal(SIGTERM, sigchd_exit);
}
//.....
set_sigchd()
if( ( pid = fork() ) < 0 ){
//error
}
else if( pid == 0 ){
//child
...
}
else{
chld_count++;
}
这时,在程序开始时设置信号处理函数,当子进程结束时,信号处理函数回收子进程
减少子进程计数。fork之后,父进程增加子进程计数。这样子,程序就实时的知道了
子进程的个数。也就可以对之后的fork做出一定的限制。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述