关于如何有效避免僵尸进程的一种探索。(动手写自己的http服务器)

关于如何避免僵尸进程。其实方法很多。有很多现成的解决方案。这里给出一个简单的方案。以及背后思考的过程。

设想一种最简单的http服务器:

伪代码:

当接收到一个tcp请求的时候.

fork 一个子进程去做工作。

主进程依旧在监听下面要来的请求。

这个模型实际上会导致。因为fork出来的子进程没有回收,并且父进程一直存在没有结束。导致越来越多的僵尸进程出现。

都知道子进程结束的时候会发一个sigchld信号给父进程。于是改进成增加一行代码:

signal(SIGCHLD,deal_signal);

void deal_signal()
{

  wait(NULL);

}

但是这样做。依旧会有大量的僵尸进程存在。因为如果sigchid信号不断的发往 主进程。主进程是不会维护一个队列去缓存这些信号的。

而是 直接把这些信号全部丢弃掉。从而导致我们无法避免僵尸进程的存在。

百度一下 发现很多答案都是要这么写

void deal_signal()
{

  while(waitpid(-1,NULL,WNOHANG)>0);

}

经过测试 这样写可以避免僵尸进程.因为这里 的waitpid在一个循环内。也就是说 如果有信号被丢弃。但是因为信号被丢弃 但是进程还在。

所以这个循环会一直去寻找子进程 一直到所有子进程全部被回收为止。

但是问题就出在这。

既然上面的解决方案的key是因为while。哪我们能不能写成while(wait(NULL)>0)来避免僵尸进程呢。

为了证明这个问题。我们写代码来测试一下。


#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

int main(int argc, char const *argv[])
{
int i;

pid_t pc;

void deal_signal();
signal(SIGCHLD,deal_signal);

for (i = 0; i < 100; ++i)
{

pc=fork();

switch(pc)
{
case 0:
printf(" child process is %d\n", getpid());
break;

default:
printf(" father proces is %d\n",getpid() );
continue;
}
//用来保证所有的子进程直接退出 而不是继续循环
if(pc==0)
break;

}

//这里保证 如果是父进程那么就一直阻塞。
//因为你如果不阻塞这个父进程 在shell里面跑这个程序 会立即执行完毕
//那么主进程就结束了 所以你永远也check不到有僵尸进程的存在
//因为当主进程结束的时候 那些子进程的父进程就变成了init进程
if (pc>0)
{
while(1)
{

}
}

return 0;
}

在终端1 上面运行这个程序

然后在终端2 上面 输入命令

ps -A -ostat,ppid,pid | grep -e ‘^[Zz]‘

你会发现 可以看到 我们代码生成出来的那些僵尸进程了。

于是我们更改代码:


#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

int number=0;

int main(int argc, char const *argv[])
{
int i;

pid_t pc;

void deal_signal();
signal(SIGCHLD,deal_signal);

for (i = 0; i < 100; ++i)
{

pc=fork();

switch(pc)
{
case 0:
printf(" child process is %d\n", getpid());
break;

default:
printf(" father proces is %d\n",getpid() );
continue;
}
if(pc==0)
break;

}

if (pc>0)
{
while(1)
{

}
}

return 0;
}

void deal_signal()
{
while(wait(NULL)>0)
{
number++;
printf("%d\n", number);

}

}

这个时候 我们再运行一次程序。并且在另外一个终端上面 运行命令

就会发现 是找不到僵尸进程的。

so 实际上 while(wait(NULL)>0)

这种写法 不但有效 而且更加简单方便理解。

关于如何有效避免僵尸进程的一种探索。(动手写自己的http服务器)

时间: 2024-10-10 00:51:13

关于如何有效避免僵尸进程的一种探索。(动手写自己的http服务器)的相关文章

第十九篇:处理僵尸进程的两种经典方法

前言 如果父进程没有结束,而子进程终止了.那么在父进程调用 wait 函数回收这个子进程或者父进程终止以前,这个子进程将一直是僵尸进程. 本文将提供两种方法处理这个问题. 方法一:父进程回收法 wait函数将使其调用者阻塞,直到其某个子进程终止.故父进程可调用wait函数回收其僵尸子进程.除此之外,waitpid函数提供更为详尽的功能( 增加了非阻塞功能以及指定等待功能 ),请读者自行查阅相关资料. 代码实现 1 #include <unistd.h> 2 #include <sys/w

面试题----僵尸进程的四种处理方法

l  父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起 l  如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用wait回收 l  如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号 l  还有一些技巧,就是fork两次,父进程fork一个子进程

僵尸进程和孤儿进程----概念

这里仅给出僵尸进程和孤儿进程的概念.来源<深入了解计算机系统(原书第3版)>和网上的博客,下面会给出博客来源. 前言:回收子进程 当一个进程由于某种原因终止时,内核并不是立即把它从系统中清除.相反,进程被保持在一种已终止的状态中,直到被它的父进程回收(reaped).当父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已终止的进程.从此时开始,该进程就不存在了. 1.基本概念 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitp

浅析三种特殊进程:孤儿进程,僵尸进程和守护进程.

其实有时想想linux内核的设计也蕴含着很多人生哲学,在linux中有这么几个特殊进程中,我们一开始见到它们的名字可能还会觉得很诧异,但在了解完了原理后,我们仔细想想,这样的命名也不无道理!下面我就给大家分别介绍一下这三种特殊的进程! 1.孤儿进程 如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程,这是子进程的父进程就是init进程(1号进程).其实还是很好理解的. #include <sys/types.h> #include <unistd.h> #inclu

开启子进程的两种方式,孤儿进程与僵尸进程,守护进程,互斥锁,IPC机制,生产者与消费者模型

开启子进程的两种方式 # # # 方式一: # from multiprocessing import Process # import time # # def task(x): # print('%s is running' %x) # time.sleep(3) # print('%s is done' %x) # # if __name__ == '__main__': # # Process(target=task,kwargs={'x':'子进程'}) # p=Process(tar

菜鸟随笔(3)---三种进程学习.孤儿进程.僵尸进程.守护进程

一只菜鸟横空出世,码农世界闯一闯,每天进展多一丢丢. 三种进程学习.孤儿进程.僵尸进程.守护进程 转自https://blog.csdn.net/believe_s/article/details/77040494 1.孤儿进程 如果父进程先退出,子进程还没退出那么子进程将被 托孤给init进程,这里子进程的父进程就是init进程(1号进程).其实还是很好理解的. // 父进程先子进程退出 // 子进程会被祖父进程接手并在后台运行,执行内部的代码 int main() { pid_t pid =

python全栈脱产第34天------开启进程的两种方式、join方法、进程对象其他相关的属性和方法、僵尸进程、孤儿进程、守护进程、互斥锁

一.开启进程的两种方式 方式一: from multiprocessing import Processimport time def task(name): print('%s is running' %name) time.sleep(3) print('%s is done' %name) # 在windows系统上,开启子进程的操作必须放到if __name__ == '__main__'的子代码中if __name__ == '__main__': p=Process(target=t

Linux中的僵尸进程和孤儿进程

在UNIX里,除了进程0(即PID=0的交换进程,Swapper Process)以外的所有进程都是由其他进程使用系统调用fork创建的,这里调用fork创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,因而除了进程0以外的进程都只有一个父进程,但一个进程可以有多个子进程.        操作系统内核以进程标识符(Process Identifier,即PID)来识别进程.进程0是系统引导时创建的一个特殊进程,在其调用fork创建出一个子进程(即PID=1的进程1,又称init)

孤儿进程和僵尸进程

孤儿进程和僵尸进程 一.定义:什么是孤儿进程和僵尸进程 僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出.这个子进程就是僵尸进程. 孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作. 僵尸进程将会导致资源浪费,而孤儿则不会. 子进程持续10秒钟的僵尸状态(EXIT_ZOMBIE)------------------------------