Linux c/c++进程之僵尸进程和守护进程

简介: 这篇文章介绍了Linux系统中僵尸进程和守护进程的概念、产生原因、解决方法以及如何创建守护进程。

1. 僵尸进程

1.1 僵尸进程的定义:

   父进程创建了子进程,而子进程先于父进程结束,子进程的资源没有被释放,就会变成僵尸进程,持续占用系统资源

1.2 僵尸进程的解决办法

   子进程在结束之前会向父进程发送SIGCHLD信号,父进程接收到信号之后,先回收子进程资源,然后父进程自己再结束

   想要防止僵尸进程的情况出现,可以在父进程中写一个wait函数(或者waitpid函数)等待子进程发送的SIGCHLD信号

无wait()函数的情况:

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

int main(){
    if(fork()){
        printf("子进程被创建!\n");
    }else{
        for(int i = 0;i<5;i++){
            printf("子进程执行:%d\n",i+1);
            sleep(1);
        }
    }
    printf("父进程结束!\n\n");
    return 0;
}

运行结果:

 从上面的输出结果可以看出,在没有wait()函数的情况下,父进程并不会等待子进程结束之后再执行"父进程结束!"这句话,如果在此时父进程在子进程未结束前被强制结束,那么就会造成僵尸进程的情况出现

有wait()函数的情况:

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

int main(){
    if(fork()){
        printf("子进程被创建!\n");
        wait(0);
    }else{
        for(int i = 0;i<5;i++){
            printf("子进程执行:%d\n",i+1);
            sleep(1);
        }
    }
    printf("父进程结束!\n\n");
    return 0;
}

运行结果:

   当存在wait()函数时,父进程会等待子进程发送的SIGCHLD信号,当父进程接收到信号之后,先回收子进程资源,父进程再结束

2.守护进程

2.1 守护进程概念

独立记录其它进程的情况,记录操作系统日志等

2.2 守护进程的查看方法

ps -axj

TPGID为 -1 的是守护进程

2.3 守护进程的创建

2.3.1 守护进程的功能实现和其它进程一样

2.3.2 将一个进程变为守护进程的步骤

  • 干掉其父进程
  • 摆脱终端控制(关闭0 1 2 文件描述符并重定向当前进程的io操作到 /dev/NULL (黑洞设备))
  • 摆脱原有会话,进程组的控制从而创建新的会话

2.4 创建守护进程编程模型

2.4.1 创建守护进程方式一

  1. 创建新会话 setsid()函数
  2. 改变当前工作目录 chdir()函数
  3. 重设当前文件权限 umask()函数
  4. 关闭文件 close()函数

    2.4.2 创建守护进程方式二

  5. 重设文件权限 umask()函数

  6. 创建子进程 fork()函数
  7. 结束父进程
  8. 创建新会话 setsid()
  9. 防止子进程成为僵尸进程 signal()函数忽略掉SIGCHLD SIGHUP信号
  10. 改变当前工作目录 chdir()函数
  11. 重定向文件描述符号 open()函数 dup2()函数
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(){
    // 1. 重设文件权限
    umask(0);
    // 2. 创建子进程
    int ret = fork();
    if(ret < 0) printf("创建进程失败:%m"),exit(-1);
    if(ret > 0) printf("父进程结束:%m\n"),exit(0);     // 3. 让父进程结束
    if(0 == ret){
        printf("pid:%d\n",getpid());
        // 4. 创建新会话
        setsid();
        // 5. 防止子进程成为僵尸进程   忽略掉SIGCHLD SIGHUP信号
        signal(SIGCHLD,SIG_IGN);
        signal(SIGHUP,SIG_IGN);
        // 6. 改变当前工作目录
        chdir("/");
        // 7. 重定向文件描述符号
        int fd = open("/dev/NULL",O_RDWR);
        dup2(fd,0);
        dup2(fd,1);
    }

    while(1){
        //做事情(模拟守护进程工作)
        sleep(1);
    }

    return 0;
}

结果:

关闭守护进程:

由此可知上方创建的pid为3469的守护进程已经被关闭

2.5 进程的组织形式

多个进程组成一个进程组

多个进程组组成一个会话

注: 进程组的组长 session进程

2.6 守护进程的关闭

直接使用kill 2 pid 将指定进程干掉即可

2.7 终端标准输入输出设备

  • 0 标准输入设备
  • 1 标准输出设备
  • 2 标准错误输出设备
相关文章
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
435 16
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
314 0
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
381 0
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
253 0
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
323 0
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
570 12
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
301 0
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
478 0

热门文章

最新文章