僵尸进程最优解

Posted 漂亮姐姐1

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了僵尸进程最优解相关的知识,希望对你有一定的参考价值。

前言

什么是僵尸进程?

当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程,直到父进程结束,僵尸进程的资源才会被释放。

僵尸进程产生的原因

父子进程运行是一个异步的过程,为了使得父进程在子进程退出时,仍可以获得子进程的状态信息,Unix不会直接释放进程的所有资源。当子进程退出时,内核释放子进程的用户资源,包括打开的文件,占用的内存等,但是仍然为其保留一定的信息,包括进程号(Process ID),退出状态(Termination Status),运行时间(Runtime)等。

这样,父进程就可以通过调用wait/waitpid来获取子进程的状态信息同时释放子进程资源,但如果不调用wait/waitpid,系统资源将被占用,可能导致系统无法产生新的进程。

正文

正如上文提到的,可以使用wait/waitpid来将僵尸进程资源回收
可以在父进程中调用wait/waitpid,或者捕获SIGCHLD再调用wait/waitpid

需要注意:

  • 调用wait/waitpid函数时,如果没有僵尸子进程,但仍有子进程,父进程会阻塞,直到有子进程死亡,变成僵尸进程
  • wait/waitpid 一次返回一个子进程的状态信息,有多个进程需要调用多次
  • 多线程阻塞在wait/waitpid时,仅有一个线程会返回子进程状态信息

大多时候我们都希望父子进程异步工作,而不是阻塞等待子进程结束,下面是捕获SIGCHLD的示例:

void handle(int sig)
	printf("catch signal %d\\n",sig);
	wait(NULL); // 可以传入结构体,并调用不同函数获取特定的信息,具体看手册
	printf("Child process exit\\n");


int main()
	int pid = fork();
	if(pid > 0)
		signal(SIGCHLD,handle);
		// 父进程工作
	else if(pid == 0)
	// 子进程工作
	

但是这里忽略了SIGCHLD信号的产生条件,SIGCHLD信号在子进程终止,挂起,被唤醒时会向父进程发出
如果子进程接收到挂起信号,父进程进入handle处理函数,父进程将阻塞在wait/waitpid

如果我们不关心子进程的执行情况,最简单直接的方法就是忽略SIGCHLD信号,让子进程结束后由init接管,init进程会释放掉所有僵尸进程的资源。

signal(SIGCHLD,SIG_IGN);

思考一下,忽略SIGCHLD信号是否对程序有影响,SIGCHLD信号产生条件:终止,挂起,唤醒

其中挂起信号(SIGSTOP),SIGKILL信号无法捕获,所以忽略SIGCHLD信号对这两个没影响
但是假如我们希望捕获SIGCONT信号,生成日志,那么我们就不能简单忽略SIGCHLD信号

个人认为更科学的做法是
使用sigaction,并设置sa_flags标志位为SA_NOCLDWAIT
这样,当子进程终止(terminate)时,子进程不会被设置为僵尸进程

struct sigaction sa;
memset(&sa,0,sizeof(sa));
sa.sa_handler = SIG_DFL;  // 也可以自定义handler函数
sa.sa_flags = SA_NOCLDWAIT;
sigaction(SIGCHLD,&sa,NULL);

tips:
当使用 -std=c99 编译时,会找不到sigaction结构体,解决方法:添加头文件<bits/sigaction.h>
也可以使用 -std=gnu99 编译

另外也有别的技巧,调用两次fork函数,然后子进程退出,孙进程由系统接管

int pid;
if ((pid = fork()) == 0)
	if ((pid = fork()) > 0)
		exit(0); // 子进程退出
	else
		// 孙进程工作
	

else
	// 父进程工作

仅做记录,最好的方法还是使用sigaction

以上是关于僵尸进程最优解的主要内容,如果未能解决你的问题,请参考以下文章

僵尸进程最优解

僵尸进程最优解

matlab求解最优解

AI跨界,RPA进阶,数字员工会是企业转型的最优解吗?

matlab随机变量为一般分布,如何搜索最优解

梯度下降——寻找那个最优解