进程控制、孤儿进程和僵尸进程

一、进程控制

  1、进程标识

1、操作系统里每打开一个进程都会创建一个进程ID,这是唯一标识进程的编号,即PID。

2、PID 在任何时刻都是唯一的,但是可以重用。当进程终止并被回收以后,其 PID 就会被系统回收

3、进程的 PID 由系统内核根据延迟重用算法生成,以确保新进程的 PID 不同于最近终止进程的 PID。

4、进程PID的最大值是有限的(因系统的不同而不同),需要及时回收

2、特殊进程

0 号进程:通常是调度进程,常常被称为交换进程(swapper)。该进程是内核的一部分,所有进程的根进程,它并不执行任何磁盘上的程序,因此也被称为系统进程。
1 号进程:通常是 init 进程,在自举过程结束时由内核调用。
2 号进程:页守护进程:负责虚拟内存系统的分页操作

3、进程相关函数

1、创建新进程(子进程)--fork()

  当调用fork()时,将执行以下动作:

1、向系统申请一个新PID

2、创建子进程,复制父进程的PCB,获得父进程的数据空间、堆、栈等资源的副本(但不是共享资源)

3、在父进程中返回子进程的PID,在子进程中返回0

执行完以上动作后,父进程和子进程便开始并发执行了。

注意:fork()函数可能有三种不同的返回值,并且调用一次,会返回两个值:

1、返回0,表示当前在子进程中运行

2、返回创建子进程的PID,表示当前在父进程中运行

3、返回一个负数,表示创建进程失败

为什么调用fork()一次会返回两个不同的值?

调用fork()函数之前,只有一个进程在运行(父进程),调用之后有两个进程在运行,分别是父进程和子进程,注意,这个时候父进程和子进程都处于fork()函数之后的位置,不同的是父进程调用了fork()函数创建了子进程,但是子进程还没有调用fork()函数创建自己的子进程,所以这两个进程执行下去会返回不同的值

用代码举个例子

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main ()
{
    pid_t fpid; //fpid表示fork函数返回的值
    int count=0;
    fpid=fork();
    //假设这里有一个断点,父进程调用了fork()函数产生了子进程,
    //但是子进程没有调用产生自己的子进程,所以父、子进程往下运行时会有不同的返回值
    if (fpid < 0)
        printf("error in fork!");
    else if (fpid == 0) {
        printf("i am the child process, my process id is %d/n",getpid());
        printf("我是爹的儿子/n");//对某些人来说中文看着更直白。
        count++;
    }
    else {
        printf("i am the parent process, my process id is %d/n",getpid());
        printf("我是孩子他爹/n");
        count++;
    }
    printf("统计结果是: %d/n",count);
    return 0;
}  

同时,根据父进程和子进程返回的值不同,我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

2、exec()函数:加载新程序取代当前运行进程,pid保持不变

3、exit()函数:程序退出函数。返回0表示正常退出,其它退出异常

4、wait()函数:

功能(解决僵尸进程的方法)

父进程一旦调用了wait就立即阻塞自己,由wait自动分析当前进程的某个子进程是否已经正常退出,如果让它找到了这样一个已经变成僵尸的子进程(异常),wait就会收集这个子进程的信息,并把它彻底销毁后返回,并唤醒父进程;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。

 

二、孤儿进程和僵尸进程(进程终止最终是资源的回收)

1、孤儿进程:

父进程早于子进程退出时候子进程还在运行,子进程会成为孤儿进程。linux会对孤儿进程的处理,把孤儿进程的父进程设为1,也就是由init进程来托管。init进程负责子进程退出后的善后清理工作。

2、僵尸进程:

子进程退出后留下的进程信息没有被收集,会导致占用的进程控制块PCB不被释放,形成僵尸进程。进程已经死去,但是进程资源没有被释放掉。

3、问题及危害

  1、孤儿进程的资源收集由init进程负责,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会处理它的一切善后工作。因此孤儿进程并不会有什么危害。

2、如果系统中存在大量的僵尸进程,他们的进程号就会一直被占用,但是系统所能使用的进程号是有限的,系统将因为没有可用的进程号而导致系统不能产生新的进程.。

  任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个
子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时
处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。 
如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状程的身份对僵尸状态的子进程进行处理。

4、怎样避免僵尸进程

1、通过signal(SIGCHLD, SIG_IGN)通知内核对子进程的结束不关心,由内核回收。如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。

2、父进程调用wait/waitpid等函数等待子进程结束,如果尚无子进程退出wait会导致父进程阻塞waitpid可以通过传递WNOHANG使父进程不阻塞立即返回

3、通过两次调用fork。父进程首先调用fork创建一个子进程然后waitpid等待子进程退出,子进程再fork一个孙进程后退出。这样子进程退出后会被父进程等待回收,而对于孙子进程其父进程已经退出所以孙进程成为一个孤儿进程,孤儿进程由init进程接管,孙进程结束后,init会等待回收。

4、杀死父进程。 如果僵尸进程的父进程还存在,找到这个父进程,kill掉它。这样就会变成3的情况,init会负责善后工作。

部分转载自https://www.cnblogs.com/sinpo828/p/10913249.html

原文地址:https://www.cnblogs.com/-citywall123/p/12403424.html

时间: 2024-10-07 04:58:37

进程控制、孤儿进程和僵尸进程的相关文章

进程——wait与waitpid、僵尸进程与孤儿进程

僵尸进程:子进程终止了,但是父进程没有回收子进程的资源PCB.使其成为僵尸进程 孤儿进程:父进程先与子进程结束了,使得子进程失去了父进程,这个时候子进程会被1号进程init进程领养,成为孤儿进程 为了防止上面两种情况,我们应当在父进程结束之前一定要回收子进程的所有资源 所以出现了wait和waitpid #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t

Linux进程实践(4) --wait避免僵尸进程

Wait的背景 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止) 子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态. 父进程查询子进程的退出状态可以用wait/waitpid函数 #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t wa

UNIX高级环境编程(11)进程控制(Process Control)- 进程快照,用户标识符,进程调度

1 进程快照(Process Accounting) 当一个进程终止时,内核会为该进程保存一些数据,包括命令的小部分二进制数据.CPU time.启动时间.用户Id和组Id.这样的过程称为process accounting,本篇译为进程快照. 函数acct可以打开或关闭进程快照功能. 负责记录快照的数据结构如下所示: 成员说明: ac_flag成员记录进程执行过程中的特定事件(稍后的表中会详细说明): 进程创建时,初始化进程快照的数据在进程表(process table)中,但是只有在进程终止

MongoDB 进程控制系列二:结束进程

1:如果某个进程产生了异常,可以考虑将其kill掉 db.killOp(10417) db.killOp(10417/*opid*/) 等同于: db.$cmd.sys.killop.findOne({op:10417}) 2:注意: 不要kill内部发起的操作,比如replica set发起的sync操作等.

第7章 进程关系(1)_守护、孤儿和僵尸进程

1. 守护.孤儿和僵尸进程 (1)守护进程 ①守护进程(daemon)是生存期长的一种进程.它们常常在系统引导装入时启动,在系统关闭时终止. ②所有守护进程都以超级用户(用户ID为0)的优先权运行. ③守护进程没有控制终端 ④守护进程的父进程都是init进程(1号进程). (2)孤儿进程:父进程先结束,子进程就成为孤儿进程,会由1号进程(init进程)领养. [编程实验]产生孤儿进程 //process_orphen.c #include <unistd.h> #include <std

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)------------------------------

孤儿进程与僵尸进程

1. 基本概念: 孤儿进程:父进程退出,但是其子进程仍然在运行,那么这些子进程被称为孤儿进程:孤儿进程会被init进程收养,并作善后处理: 僵尸进程:一个已经终止,但是其父进程尚未对齐进行善后处理的进程被称为僵尸进程:ps命令状态为Z的进程: 善后处理:内核为每个终止子进程保存了一定量的信息,这些信息至少包括进程ID,该进程的终止状态,以及进程使用的CPU时间总量.如果父进程没有使用wait或者waitpid获取终止子进程有关信息,这些信息将一直保存,直到父进程处理后才能释放它仍占有的资源: 2

关于孤儿进程和僵尸进程的实践

首先关于孤儿进程 processA   processB   processC ps -ef|grep process sroot     9665 24982  0 23:42 pts/0    00:00:00 /bin/bash ./processA.sh sroot     9666  9665  023:42 pts/0    00:00:00 /bin/bash./processB.sh sroot     9667  9666  023:42 pts/0    00:00:00 /