孤儿进程:
父进程退出后,还在继续运行的这些子进程,被称为孤儿进程;
孤儿进程会被init进程所收养,并由init进程对他们完成状态收集。
正常情况下,子进程结束,会释放掉所有内存,但是进程号,退出状态,和运行时间在子进程结束后并没有被释放,而是需要其父进程调用wait()或waitpid(),才能进行释放。
僵尸进程:
一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
产生僵尸进程的原因:
1.父进程没有接收子进程结束后抛出 的SIGCHLD信号函数,也就是说,父进程没有调用wait()/waitpid()来获取子进程的退出状态,也就没存对进程描述符进行处理。
2.父进程有调用wait()/waitpid()函数,但当子进程已终止时父进程还没有执行到wait()/waitpid()函数这一步,此时子进程也时僵尸进程。
僵尸进程如何解决:
1.使用fork两次,用孙子进程完成子进程的任务:
①父进程fork()后产生一个子进程,随后就立即执行waitpid()/wait()函数来等待子进程结束。
②然后子进程fork()后产生一个孙子进程,立即执行exit(0)结束子进程,然后父进程继续指向,由于孙子进程失去了它的父进程,那么孙子进程变为孤儿进程。
③孙子进程先要指行sleep(n)这步操作,否则他可能会比他的父进程先指行,那么打印出来的ID是创建它的ID,而不是init的ID,因为在操作系统中父子进程执行的先后顺序不能确定。
④这样孙子进程来执行它父进程需要的事件,而不会有僵尸进程出现。(父子进程共享代码段),而且,孙子进程后期的状态有init进程进行处理。
2.让僵尸进程成为孤儿进程,由init进程回收;(手动杀死父进程)
3.捕捉SIGCHLD信号,并在信号处理函数中调用wait函数;
子进程在结束后会发出信号,我们需要对这个信号进行捕捉,在捕捉到后,使用wait()或者waitpid()函数对子进程进行处理,这样就不用阻塞父进程了。