Linux中的进程控制:进程退出、孤儿进程、僵尸进程 概念及代码示例 [Linux高并发服务器开发]

目录

一、进程退出

二、孤儿进程

三、僵尸进程


一、进程退出

#include <stdlib.h>
void  exit ( int status );


#include <unistd.h>
void  _exit ( int status );

退出进程 是 调用exit函数 ,C语言标准库中 exit() 函数 , linux操作系统提供 _exit()。它们都可以用于进程退出,但是它们是由区别的。如下面的示意图:

C语言中的 exit()函数执行,在调用 _exit()系统函数之前,会刷新 I/O缓冲,关闭文件描述符。 而直接调用 _exit() 函数,会直接终止进程。

代码示例,解释exit 与 _exit 的区别:

1.调用 exit 函数

/*
    #include <stdlib.h>
    void exit(int status);

    #include <unistd.h>
    void _exit(int status);

    status参数:是进程退出时的一个状态信息,父进程回收子进程资源的时候,可以获取到。

*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
    printf("hello\n");//带换行符\n,内部会自动刷新IO缓冲区
    printf("world");//写到缓冲区中,但是没进行IO刷新,把数据刷新到显示台

    exit(0);

    return 0;
}

执行结果如下:

        把没有带 \n 的word也输出到显示终端,因为调用exit()函数,在结束进程前,会进程缓冲区IO刷新。

2.调用 _exit 函数

#include <stdio.h>
#include <unistd.h>
int main()
{
    printf("hello\n");//带换行符\n,内部会自动刷新IO缓冲区
    printf("world");//写到缓冲区中,但是没进行IO刷新,把数据刷新到显示台

    _exit(0);

    return 0;
}

执行结果如下:

直接调用 _exit()函数结束进程, 不会在结束前,将缓冲区数据进行IO刷新到显示终端。

二、孤儿进程

父进程运行结束,但子进程还在运行(未运行结束),这样的子进程就 称为 孤儿进程(Orphan Process)。( 没了原来父进程的 子进程

每当出现一个孤儿进程的时候,内核就把孤儿进程的父进程设置为 init ,而 init进程会循环地 wait() 释放它的已经退出的子进程的资源。 这样,当一个孤儿进程凄凉地结束了其生命周期的时候, init 进程就会处理释放孤儿进程的PCB资源。

因此孤儿进程并不会有什么危害。
 

孤儿进程,代码示例:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    pid_t pid = fork();
    if(pid>0)
    {
        printf("I am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
    }
    else if(pid == 0)
    {
        //当前是子进程
        sleep(4);
        printf("I am child process, pid:%d ppid:%d\n",getpid(),getppid());
       
    }

    //父子进程都会执行
    for(int i =0 ;i<3;++i)
    {
        printf("i:%d ,pid:%d\n",i,getpid());
        sleep(1);
    }

    return 0;
}

执行结果:

 父进程的运行都结束了, 子进程还没有运行结束。 并且子进程的 父进程ppid变为了1。 就是子进程是孤儿进程,内核就把孤儿进程的父进程设置为 init ,init进程的id是1,而 init进程会循环地 wait() ,回收它的已经退出的子进程的资源。

3157是当前终端进程的ID,当orphan主进程,结束后,会由后端转向前端,即当前终端。那么为什么子进程的数据也会显示在当前终端呢? 是以为子进程 在fork的时候,会与父进程共享一些数据,文件描述符表等,所以显示在当前终端。

三、僵尸进程

每个进程结束之后, 都会释放自己地址空间中的用户区数据内核区的 PCB 没有办法自己释放掉,需要父进程去释放。
进程终止时,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。

僵尸进程不能被 kill -9 杀死,这样就会导致一个问题,如果父进程不调用 wait()或 waitpid() 的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的(0~32767),如果大量的产生僵尸进程,将因为没有可用的进程号而导致系统不能产生新的进程,此即为僵尸进程的危害,应当避免。
 

代码示例:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    pid_t pid = fork();
    if(pid>0)
    {
        while(1)
        {
            printf("I am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
            sleep(1);
        }
        
    }
    else if(pid == 0)
    {
        //当前是子进程
        printf("I am child process, pid:%d ppid:%d\n",getpid(),getppid());
       
    }

    //父子进程都会执行
    for(int i =0 ;i<3;++i)
    {
        printf("i:%d ,pid:%d\n",i,getpid());
        sleep(1);
    }

    return 0;
}

执行结果:

 通过ps  aux ,查看进程状态:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值