孤儿僵尸守护进程

孤儿僵尸守护进程

  • 1. 孤儿进程:
  • 2. 僵尸进程:
  • 3. 守护进程:==(重点)==

1. 孤儿进程:

父进程退出,还没退出的子进程就变成了孤儿进程

不要怕,还有爷爷进程init:
孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
省流:父先退出,但子还未退出

想想我们如何模仿一个孤儿进程? 答案是: kill 父进程!

杀死某个可执行文件全部的进程
killall 可执行文件名

干点这个进程号
kill -9 进程号

查看mp1.exe这个可执行文件有哪些进程正在执行
ps -ef | grep mp1.exe
可以用下面这个程序进行模拟
// 模拟孤儿进程
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>

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

typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);

int main(int argc, char **argv)
{
    start_worker_processes(4); // 4核cpu
                               // 管理子进程
    wait(NULL);
    // printf("parent is over!\n");
    // return 0;
}

void start_worker_processes(int n)
{
    int i = 0;
    for (i = n - 1; i >= 0; i--)
    {
        spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
    }
}

pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{

    pid_t pid;
    pid = fork();

    switch (pid)
    {
    case -1:
        fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
        return -1;
    case 0:
        proc(data);
        return 0;
    default:
        break;
    }
    printf("start %s %ld\n", name, (long int)pid);
    return pid;
}

static void worker_process_init(int worker)
{
    cpu_set_t cpu_affinity; // cup亲人
    // worker = 2;
    // 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3
    CPU_ZERO(&cpu_affinity);
    CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3
    // sched_setaffinity
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
    {
        fprintf(stderr, "sched_setaffinity() failed\n");
    }
}

void worker_process_cycle(void *data)
{
    int worker = (intptr_t)data;
    // 初始化
    worker_process_init(worker);

    // 干活
    for (;;)
    {
        sleep(10);
        printf("pid %ld ,doing ...\n", (long int)getpid());
    }
}

2. 僵尸进程:

一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
  省流:子先退出,父未调用wait或waitpid

  1. 怎么查看僵尸进程:
      利用命令ps,可以看到有标记为的进程就是僵尸进程。
    在这里插入图片描述
  2. 怎样来清除僵尸进程:
    干掉父进程,子进程会有init来回收
eg:
// 模拟僵尸进程
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>

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

typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);

int main(int argc, char **argv)
{
    start_worker_processes(4); // 给虚拟机配置了2核
    // 管理子进程
    // wait(NULL);
    for (;;) // 父不退出,子退出时父不使用wait或waitpid进行回收=>僵尸进程
    {
        sleep(1);
    }

    return 0;
}

void start_worker_processes(int n)
{
    int i = 0;
    for (i = n - 1; i >= 0; i--)
    {
        spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
    }
}

pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{

    pid_t pid;
    pid = fork();

    switch (pid)
    {
    case -1:
        fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
        return -1;
    case 0:
        proc(data);
        return 0;
    default:
        break;
    }
    printf("start %s %ld\n", name, (long int)pid);
    return pid;
}

static void worker_process_init(int worker)
{
    cpu_set_t cpu_affinity; // cup亲人
    // worker = 2;
    // 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3
    CPU_ZERO(&cpu_affinity);
    CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3
    // sched_setaffinity
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
    {
        fprintf(stderr, "sched_setaffinity() failed\n");
    }
}

void worker_process_cycle(void *data)
{
    int worker = (intptr_t)data;
    // 初始化
    // worker_process_init(worker);
    exit(1); // 子进程退出
    // 干活
    /*for (;;)
    {
        sleep(10);
        printf("pid %ld ,doing ...\n", (long int)getpid());
    }*/
}

3. 守护进程:(重点)

不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务。守护进程脱离于终端,是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断(比如关闭终端等)。

那如何成为一个守护进程呢? 步骤如下:

  1. 调用fork(),创建新进程,它会是将来的守护进程.
  2. 在父进程中调用exit,保证子进程不是进程组长
  3. 调用setsid()创建新的会话区
  4. 将当前目录改成根目录(如果把当前目录作为守护进程的目录,当前目录不能被卸载他作为守护进程的工作目录)
  5. 将标准输入,标准输出,标准错误重定向到/dev/null.
    我们来看这个代码:
//守护进程示例
#include <fcntl.h>
#include <unistd.h>

//生成一个守护进程,以后要生成一个守护进程直接复制这个函数daemon(0,0)
int daemon(int nochdir, int noclose)//0 0
{
    int fd;

    switch (fork()) {
    case -1://错误
        return (-1);
    case 0://子进程
        break;
    default://父进程
        _exit(0);
    }

    if (setsid() == -1)
        return (-1);

    if (!nochdir)//!0 = 1
        (void)chdir("/");//将当前目录改成根目录

	//!0 = 1
    if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
        (void)dup2(fd, STDIN_FILENO);//将标准输入,标准输出,标准错误重定向到/dev/null.
        (void)dup2(fd, STDOUT_FILENO);
        (void)dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)close (fd);//重定向之后就干掉fd
    }
    return (0);
}

eg:
// 模拟守护进程
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>

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

#include <sys/stat.h>
#include <fcntl.h>

typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);

// 生成一个守护进程
int daemon(int nochdir, int noclose) // 0 0
{
    int fd;

    switch (fork())
    {
    case -1: // 错误
        return (-1);
    case 0: // 子进程
        break;
    default: // 父进程
        _exit(0);
    }

    if (setsid() == -1)
        return (-1);

    if (!nochdir)         //! 0 = 1
        (void)chdir("/"); // 将当前目录改成根目录

    //! 0 = 1
    if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1)
    {
        (void)dup2(fd, STDIN_FILENO); // 将标准输入,标准输出,标准错误重定向到/dev/null.
        (void)dup2(fd, STDOUT_FILENO);
        (void)dup2(fd, STDERR_FILENO);
        if (fd > 2)
            (void)close(fd); // 重定向之后就干掉fd
    }
    return (0);
}

int main(int argc, char **argv)
{
    start_worker_processes(4); // 4核cpu
                               // 管理子进程
    wait(NULL);
    // printf("parent is over!\n");
    // return 0;
}

void start_worker_processes(int n)
{
    int i = 0;
    for (i = n - 1; i >= 0; i--)
    {
        spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
    }
}

pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{
    daemon(0, 0); // 成为守护进程//
    pid_t pid;
    pid = fork();

    switch (pid)
    {
    case -1:
        fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
        return -1;
    case 0:
        proc(data);
        return 0;
    default:
        break;
    }
    printf("start %s %ld\n", name, (long int)pid);
    return pid;
}

static void worker_process_init(int worker)
{
    cpu_set_t cpu_affinity; // cup亲人
    // worker = 2;
    // 多核高并发处理  4core  0 - 0 core 1 - 1  2 -2 3 -3
    CPU_ZERO(&cpu_affinity);
    CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3
    // sched_setaffinity
    if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
    {
        fprintf(stderr, "sched_setaffinity() failed\n");
    }
}

void worker_process_cycle(void *data)
{
    int worker = (intptr_t)data;
    // 初始化
    worker_process_init(worker);

    // 干活
    for (;;)
    {
        sleep(10);
        printf("pid %ld ,doing ...\n", (long int)getpid());
    }
}

wxncom@wxncom-virtual-machine:~/shared_bike/demo/fork_demo$ gcc multip_process_3.c -o mp3.exe
wxncom@wxncom-virtual-machine:~/shared_bike/demo/fork_demo$ ./mp3.exe
wxncom@wxncom-virtual-machine:~/shared_bike/demo/fork_demo$ ps -ef | grep mp3.exe
wxncom     3023      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3025      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3027      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3028      1  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3029   3028  0 17:21 ?        00:00:00 ./mp3.exe
wxncom     3034   1646  0 17:23 pts/1    00:00:00 grep --color=auto mp3.exe

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/24566.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL主从复制配置

一、MySQL主从概念二、主库配置&#xff08;Master&#xff09;第一步:修改Mysql数据库的配置文件/etc/my.cnf第二步:重启Mysql服务 systemctl restart mysqld第三步:登录Mysql数据库&#xff0c;执行下面SQL第四步:登录Mysql数据库&#xff0c;执行下面SQL&#xff0c;记录下结…

解决node上传文件乱码问题终极方案

问题描述 今天在菜鸟教程学习node上传文件时遇到了一个中文乱码的问题&#xff0c;文件名包含中文就会显示乱码&#xff0c;上传到服务器的文件名也是乱码。试了两个方法都不行&#xff0c;最后还是问了万能的度娘才解决。 我做了一个非常简单的上传文件的界面&#xff0c; …

介绍10款ChatGPT替代产品

ChatGPT 引领着聊天 AI 的世界&#xff0c;许多人已经开始在日常生活中使用它。OpenAI 的 GPT-3 语言模型是聊天机器人的基础&#xff0c;它使得用户能够通过回答问题与 AI 进行交互。 GPT-4 的引入为机器人提供了更强大的功能。然而&#xff0c;它也有一个明显的缺点&#xff…

19-02 基于业务量级的架构技术选型演进

从零开始——单服务应用 单体应用技术选型 &#xff08;GitHub、Gitee…&#xff09;搜索是否有线程的产品用最熟悉的技术&#xff0c;最快的速度上线如果有经费&#xff1a;考虑商业化解决方案 个人小程序怎么做技术选型的 搜索是否有快速搭建下程序的软件技术选型 后端技…

python 网络编程和http协议--网络编程,HTTP协议,Web服务器

一.网络编程 1.IP地址 给网络中的每一台设备进行编号. IPV4 IPV6 2.端口和端口号 端口的作用就是给运行的应用程序提供传输数据的通道。 端口号的作用是用来区分和管理不同端口的&#xff0c;通过端口号能找到唯一个的一个端口。 3.TCP协议 协议: 双方的约定. 网络传输协…

代码线程安全

线程生命周期 synchronized synchronized会自动释放锁 synchronized同步代码块 synchronized后面括号里obj是锁对象(保证唯一)&#xff1b;static修饰的obj对象是自定义MyThread线程类的静态成员变量&#xff0c;该自定义线程类所有实例共享保证锁对象唯一性&#xff1b;另一…

博客系统的后端设计(八) - 实现发布博客功能

文章目录 发布博客1. 约定前后端交互接口2. 服务器代码3. 客户端代码4. 出现的问题 发布博客 在原来的编辑页面点击发布文章按钮&#xff0c;是不会有什么效果的。 这是因为此时还不能实现前后端的交互。 1. 约定前后端交互接口 请求使用 POST&#xff0c;路径是 /blog title这…

Niagara—— Niagara Editor界面

目录 一&#xff0c;菜单栏 二&#xff0c;工具栏 三&#xff0c;预览面板 四&#xff0c;参数面板 五&#xff0c;系统总览面板 六&#xff0c;暂存区面板 七&#xff0c;选择面板 八&#xff0c;时间轴面板 九&#xff0c;曲线面板 十&#xff0c;日志面板 十一&a…

通过js来判断是否是横屏如果是就自刷新页面解决横屏之后只有屏幕一半宽度的问题

判断页面是横屏还是竖屏 window.addEventListener("load", rotate, false);window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", rotate, false);function rotate() {if (window.orientatio…

力扣高频SQL50题(基础版)——第一天

力扣高频SQL50题(基础版)——第一天 1 可回收且低脂的产品 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # WHERE子句中使用多条件 SELECT product_id FROM Products WHERE low_fatsY AND recyclableY1.3 运行截图 2 寻找用户推荐人 2.1 题目内容…

《数据库应用系统实践》------ 小区停车管理系统

系列文章 《数据库应用系统实践》------ 小区停车管理系统 文章目录 系列文章一、需求分析1、系统背景2、 系统功能结构&#xff08;需包含功能结构框图和模块说明&#xff09;3&#xff0e;系统功能简介 二、概念模型设计1&#xff0e;基本要素&#xff08;符号介绍说明&…

第13届蓝桥杯Scratch选拔赛真题集锦

第13届蓝桥杯Scratch选拔赛真题集锦 编程题 第 1 题问答题 跳舞机游戏 题目说明 编程实现 跳舞机游戏。 具体要求: 1).点击绿旗,舞台左上角显示得分0代表玩家分数,在得分右侧倒计时10代表游戏时长(10s) 2).游戏开始倒数计时,在舞台上随机显示上、下、左、右四个箭头中…

SCMA基本原理介绍

SCMA: Sparse Code Multiple Access SCMA基本原理 我们考虑一个同步&#xff08;synchronous&#xff09;的SCMA系统&#xff0c; 含1个基站&#xff08;Base Station, BS&#xff09;&#xff1b; J J J个用户&#xff08;so called layers&#xff09;&#xff1b;K个OFDM…

vue2介绍(入门)

目录 声明式渲染 v-bind v-if条件与循环 name命名 学会log打印 一些js方法 双向绑定v-model和v-bind 那么请实现一个复选框吧 自定义标签模板 声明式渲染 我感觉这里文档的意思是双向绑定&#xff0c; 或许需要清理一下js缓存机制 &#xff0c;嗯...不懂,响应式&…

深入解析Linux C/C++ 编程中的内存泄漏问题

深入解析Linux C/C 编程中的内存泄漏问题 I. 前言 (Introduction)1.1 文章目的与内容概述 (Purpose and Overview of the Content)1.2 重要性和实用性的说明 (Significance and Practicality Explanation)1.3 数据结构与内存泄漏的基本概念 (Basic Concepts of Data Structure …

PDF文件数字证书签名指南

一、安装PDF证书的环境 1.1 PDF证书安装环境 Windows pc 机一台 安装Adobe Acrobat 软件 PDF文档签名证书一张(备注&#xff1a;本指南使用沃通内部文档加密证书进行操作,通用其它版本证书) 1.2 网络环境要求 请确保您签名的电脑可以正常访问外网。 二、PDF证书安装 2.…

数据结构之二叉树的基本实现

在我们之前已经了解的堆这样的完全二叉树的实现&#xff0c;也对树型结构有了一些了解&#xff0c;那么今天我们来看看二叉树的一些性质。 因为二叉树是一种每个节点至多只有两个子树&#xff08;即二叉树的每个节点的度不大于2&#xff09;&#xff0c;并且二叉树的子树有左右…

Shell脚本攻略:shell函数应用

目录 一、理论 1.shell函数 2.函数传参 3.函数变量的作用范围 4.递归 5.函数位置变量与脚本位置变量区别 6.创建库 二、实验 1.实验一 一、理论 1.shell函数 &#xff08;1&#xff09;概念 将命令序列按格式写在一起&#xff0c;可方便重复使用命令序列。 ① 避免…

Docker容器与虚拟机(VM)大对比

Docker是一个开源应用容器引擎。Docker可以将应用程序与基本架构分开&#xff0c;从而快速交付软件。 传统虚拟机的运行需要占用较高的资源&#xff0c;包括磁盘空间、内存和处理器性能。每个虚拟机都需要完整的操作系统和应用程序副本&#xff0c;这在资源利用和启动时间上存…

js实现PDF 预览和文件下载

在开发过程中要求对 PDF 类型的发票提供 预览 和 下载 功能&#xff0c;PDF 类型文件的来源又包括 H5 移动端 和 PC 端&#xff0c;而针对这两个不同端的处理会有些许不同&#xff0c;下文会有所提及。 针对 PDF 预览 的文章不在少数&#xff0c;但似乎都没有提及可能遇到的问…