cpp随笔——如何实现一个简单的进程守护模块

news2024/9/22 2:12:20

前言

在前面我们已经实现过调度模块和进程的心跳模块了,而今天我们要讲的是作为服务端后台服务程序运行三个通用模块的最后一项:进程的守护模块,在开始讲解进程的守护模块之前我们首先来看究竟什么是进程的守护模块:

守护模块(有时也称为守护进程或守护服务)可以是软件架构的一部分,用于确保关键进程的稳定运行和系统的整体健壮性。

守护模块的主要职责可能包括但不限于:

  1. 进程监控:定期检查进程的状态,确认它们是否正在运行且运行正常。

  2. 异常恢复:如果检测到进程已停止或进入不稳定状态,守护模块可以采取行动,比如重启进程,以恢复服务的正常运行。

  3. 资源管理:管理进程的资源使用情况,例如内存和CPU使用率,防止资源耗尽。

  4. 日志记录和报警:记录进程的状态变化和异常情况,必要时发送警告给系统管理员。

  5. 配置更新:当系统配置发生变化时,守护模块可以负责更新相关进程的配置,并重启进程以应用新的设置。

  6. 安全和访问控制:确保进程在安全的环境中运行,限制对外部的访问,防止未授权的操作。

接下来我们来看一下,如何来实现一个简单的进程守护模块。

进程守护模块的初步实现

首先我们来看一下如何初步实现一个简单的进程守护模块,实现的流程图如下:
在这里插入图片描述

然后我们就可以着手来实现这个守护模块:

  1. 打开日志文件
    这里我们选择将日志文件名作为命令行参数输入,所以这里的实现可以向下面这样:
 clogfile logfile;
        if (logfile.open(argv[1])==false)
        {
            cout<<"log.open"<<argv[1]<<"failed."<<endl;
        }

备注:这里的的clogfile类是博主自己封装的,大家可以根据自己的代码进行修改
2. 创建/获取共享内存

int shmid=shmget((key_t)SHMKEYP, MAXNUM*sizeof(struct st_procinfo), 0666|IPC_CREAT);
if(shmid==-1)
{
  	logfile.write("shmget failed.");
}
  1. 将共享内存连接到当下进程的地址空间
struct st_procinfo *st_info=(struct st_procinfo *)shmat(shmid,0,0);
if(st_info==(void *)-1)
{
	logfile.write("shmat failed.");
}
  1. 遍历共享内存,将超时的进程进行处理
for(int i=0;i<MAXNUM;i++)
{
	if(st_info[i].pid>0)
    {
    	logfile.write("checkproc pid=%d,name=%s,timeout=%d,atime=%d",st_info[i].pid,st_info[i].name,st_info[i].timeout,st_info[i].atime); //主要用于测试
        time_t now_time=time(NULL);
        if(st_info[i].timeout<=now_time-st_info[i].atime)
        {
          logfile.write("%d号进程超时,终止。",st_info[i].pid);
          kill(st_info[i].pid,9);
        }
   }
}
  1. 将共享内存分离出进程
shmdt(st_info);

最后就有我们初步的进程守护模块的代码了:

#include "../../public/_public.h"

using namespace idc;

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        printf("\n");
        printf("Using:./checkproc logfilename\n");

        printf("Example:/root/mylib/project/tools/bin/procctl 10 /root/mylib/project/tools/bin/checkproc /tmp/log/checkproc.log\n\n");

        printf("本程序用于检查后台服务程序是否超时,如果已超时,就终止它。\n");
        printf("注意:\n");
        printf("  1)本程序由procctl启动,运行周期建议为10秒。\n");
        printf("  2)为了避免被普通用户误杀,本程序应该用root用户启动。\n");
        printf("  3)如果要停止本程序,只能用killall -9 终止。\n\n\n");
    }

        // 打开日志文件
        clogfile logfile;
        if (logfile.open(argv[1])==false)
        {
            cout<<"log.open"<<argv[1]<<"failed."<<endl;
        }

        //创建/获取共享内存
        int shmid=shmget((key_t)SHMKEYP, MAXNUM*sizeof(struct st_procinfo), 0666|IPC_CREAT);
        if(shmid==-1)
        {
            logfile.write("shmget failed.");
        }

        //将共享内存连接到进程空间
        struct st_procinfo *st_info=(struct st_procinfo *)shmat(shmid,0,0);
        if(st_info==(void *)-1)
        {
            logfile.write("shmat failed.");
        }

        //检查共享内存的进程是否超时
        for(int i=0;i<MAXNUM;i++)
        {
            if(st_info[i].pid>0)
            {
                logfile.write("checkproc pid=%d,name=%s,timeout=%d,atime=%d",st_info[i].pid,st_info[i].name,st_info[i].timeout,st_info[i].atime); //主要用于测试
                time_t now_time=time(NULL);
                if(st_info[i].timeout<=now_time-st_info[i].atime)
                {
                    logfile.write("%d号进程超时,终止。",st_info[i].pid);
                    kill(st_info[i].pid,15);
                }
            }
        }
        
        //断开共享内存的连接
        shmdt(st_info);
        return 0;
}

代码的进一步优化

上面我们只是完成了一个简单的进程守护模块,但是其实不足之处还是比较多的,接下来我们可以看看我们还可以如何来优化一下这个代码,其实主要还是对检查共享内存的进程是否超时的代码逻辑进行一个优化,我们可以根据这个流程图来看一下我们有哪些地方没有考虑到:
在这里插入图片描述
根据上面的流程,我们可以得到改进后的代码:

//检查共享内存的进程是否超时
        for(int i=0;i<MAXNUM;i++)
        {
            if(st_info[i].pid==0) continue;
            if(st_info[i].pid>0)
            {
                //logfile.write("checkproc pid=%d,name=%s,timeout=%d,atime=%d",st_info[i].pid,st_info[i].name,st_info[i].timeout,st_info[i].atime); //主要用于测试
                //向该进程发送信号0,测试进程是否存在
                int iret=kill(st_info[i].pid,0); 
                if(iret==-1)
                {
                    //进程不存在,在共享内存中删除该进程的记录
                    memset(&st_info[i],0,sizeof(struct st_procinfo));
                    continue;
                }
                //尝试检查进程是否超时
                time_t now_time=time(0);
                if(now_time-st_info[i].atime<st_info[i].timeout) continue;
                logfile.write("进程%d超时,准备终止",st_info[i].pid);
                struct st_procinfo tmp=st_info[i]; //备份进程信息
                kill(tmp.pid,15); //首先尝试正常终止进程
                for(int j=0;j<5;j++)
                {
                    int iret=kill(tmp.pid,0);
                    if(iret==-1)
                    {
                        logfile.write("进程%d正常终止成功",tmp.pid);
                        continue; //进程不存在,说明已经正常终止;
                    }
                    sleep(1); //等待1秒 
                }

                //进程仍然存在,说明进程没有正常终止,强制终止
                kill(tmp.pid,9);
                memset(&st_info[i],0,sizeof(struct st_procinfo));
                logfile.write("进程%d强制终止成功",tmp.pid);
            }
        }
        

拓展:这里有一个问题,为什么这里我们要 写struct st_procinfo tmp=st_info[i]; //备份进程信息,主要是因为在

for(int j=0;j<5;j++)
                {
                    int iret=kill(tmp.pid,0);
                    if(iret==-1)
                    {
                        logfile.write("进程%d正常终止成功",tmp.pid);
                        continue; //进程不存在,说明已经正常终止;
                    }
                    sleep(1); //等待1秒 
                }

如果在这段代码执行间隔中进程被终止,信息清零,那么后面的kill -0kill -9都是发给它自己,会造成守护模块被kill -9自己杀死自己的乌龙

结语

以上就是一个简单的守护模块的全部实现细节,下篇见!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

torch之从.datasets.CIFAR10解压出训练与测试图片 (附带网盘链接)

前言 从官网上下载的是长这个样子的 想看图片&#xff0c;咋办咧&#xff0c;看下面代码 import torch import torchvision import numpy as np import os import cv2 batch_size 50transform_predict torchvision.transforms.Compose([torchvision.transforms.ToTensor(),…

Microsoft Graph 是什么?怎么用?

Microsoft Graph 是一个统一的 API 端点&#xff0c;用于访问 Microsoft 云服务中的数据和功能&#xff0c;包括但不限于 Microsoft 365、Dynamics 365、Windows 10、Azure Active Directory (Azure AD) 和其他 Microsoft 服务。通过 Microsoft Graph&#xff0c;开发者和企业可…

钡铼高性能Modbus转EtherCAT网关BL123

随着工业4.0和物联网(IoT)概念的兴起&#xff0c;传统工厂正经历着一场深刻的变革&#xff0c;新型的网络架构&#xff0c;如EtherCAT&#xff0c;因其高速度、高精度及开放性&#xff0c;正在逐渐取代传统的现场总线技术。然而&#xff0c;这并不意味着现有基于旧协议&#xf…

引用与指针的关系

C中指针和引⽤就像两个性格迥异的亲兄弟&#xff0c;指针是哥哥&#xff0c;引⽤是弟弟&#xff0c;在实践中他们相辅相成&#xff0c;功能有重叠性&#xff0c;但是各有⾃⼰的特点&#xff0c;互相不可替代。 • 语法概念上引⽤是⼀个变量的取别名不开空间&#xff0c;指针是…

【高中数学/指数、对数】已知a=e^0.03-1,b=3/103,c=ln1.03,则a、b、c的大小关系为?

【问题】 已知ae^0.03-1,b3/103,cln1.03,则a、b、c的大小关系为&#xff1f; 【解答】 这个问题比较令人挠头&#xff0c;其背后考察的其实是对ye^x-1,yx/1x,yln(1x)的图线的高度、位置、斜率的掌握程度。 首先我们可以将三个数变成函数式&#xff1a; ae^0.03-1,b0.03/10…

医日健集团技术力量体现测试的背后

医日健集团覆盖式更新 科技日新月异的时代&#xff0c;医日健集团始终走在行业的前列。近日&#xff0c;医日健集团外勤技术人员全面对市场点位投放的数智药房进行了新系统升级和机器测试&#xff0c;这是医日健对于科技创新的最新尝试。 以客户体验为核心优化新体验 医日健集团…

window下tqdm进度条

原代码是linux下运行&#xff0c;修改后可在window下运行。 #ifndef TQDM_H #define TQDM_H#include <chrono> #include <ctime> #include <numeric> #include <ios> #include <string> #include <cstdlib> #include <iostream> #i…

帕金森病友,你们需要的维生素秘籍来啦!✨

哈喽&#xff0c;小伙伴们~ &#x1f44b; 今天来跟大家聊聊帕金森病友们应该补充哪些维生素的小知识。&#x1f4a1; 帕金森病虽然是一种神经系统疾病&#xff0c;但合理的营养补充也能在一定程度上帮助缓解病情哦&#xff01;&#x1f4aa; &#x1f34e; 维生素C&#xff1a…

初步探究Rust生态与图形界面编程

引言 Rust作为一种现代的、安全的系统编程语言&#xff0c;自2010年问世以来&#xff0c;逐渐在开发社区中崭露头角。它的内存安全保证、并发处理能力、以及无需垃圾回收机制的高性能特性&#xff0c;使得它成为了开发系统工具、网络服务、以及嵌入式系统的热门选择。然而&…

通过maven基于springboot项目构建脚手架archetype

1、引入脚手架构建的插件依赖 <!--构建脚手架archetype--><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-archetype-plugin</artifactId><version>3.2.1</version></plugin><plugin><…

Go语言---网络编程基础知识

网络协议 从应用的角度出发&#xff0c;协议可理解为“规则”&#xff0c;是数据传输和数据的解释的规则。 假设&#xff0c;A、B 双方欲传输文件。规定: 第一次&#xff0c;传输文件名&#xff0c;接收方接收到文件名&#xff0c;应答OK 给传输方;第二次&#xff0c;发送文件…

美食菜谱点评小程序

美食菜谱点评小程序 功能介绍 用户注册登录&#xff1a;注册账号&#xff0c;然后使用注册的账号登录。 资讯功能&#xff1a;用户可以任意浏览资讯列表和详细信息。 美食菜谱库&#xff1a;点击所有菜谱菜单&#xff0c;支持查看所有的菜谱信息。 菜谱查询&#xff1a;在菜谱…

网络基础知识--网络硬件设备介绍(含eNSP模拟器命令使用)

华为 eNSP 模拟器安装教程可参考&#xff1a;华为 eNSP 模拟器安装教程&#xff08;内含下载地址&#xff09;_ensp下载-CSDN博客 华为eNSP&#xff08;Enterprise Network Simulation Platform&#xff09;模拟器是一款由华为提供的免费网络仿真平台&#xff0c;主要用于模拟和…

MES实时监控食品加工过程中各环节的安全

在实时监控食品加工过程中各环节的安全风险方面&#xff0c;万界星空科技的MES&#xff08;制造执行系统&#xff09;解决方案发挥了至关重要的作用。以下是具体如何通过MES系统实现实时监控食品加工过程中各环节安全风险的详细阐述&#xff1a; 一、集成传感器与实时监控 MES…

JDK 和 JRE:它们之间的区别是什么?

JDK 和 JRE&#xff1a;它们之间的区别是什么&#xff1f; 1、JRE&#xff08;Java Runtime Environment&#xff09;1.1 JRE的主要组成部分1.2 JRE的用途 2、JDK&#xff08;Java Development Kit&#xff09;2.1 JDK的主要组成部分2.2 JDK的用途 3、总结 &#x1f496;The Be…

景联文科技以高质量多模态数据集赋能AI大模型,精准匹配提升模型性能

在人工智能的浪潮中&#xff0c;语料数据如同建筑的基石&#xff0c;其质量、规模和运用策略直接决定了AI模型的表现和应用的广泛性。 景联文科技在AI领域深耕多年&#xff0c;打磨了高质量多模态数据集&#xff0c;致力于为不同训练阶段的算法精准匹配高质量数据资源。 3000万…

AI 助力,歌词创作不再是难题

在音乐的世界里&#xff0c;歌词创作一直被视为一项充满挑战和灵感的艺术工作。然而&#xff0c;随着科技的飞速发展&#xff0c;AI 技术的出现正在悄然改变这一局面&#xff0c;让曾经困扰众多创作者的难题迎刃而解。 “妙笔生词智能写歌词软件&#xff08;veve522&#xff0…

C语言中字符串(字符数组)中含有 0x00 (‘\0‘)引发的问题和解决办法

问题 在C语言中&#xff0c;字符串是以空字符&#xff08;null character&#xff0c;即\0或0x00&#xff09;结尾的字符数组。这种设计意味着字符串中的任何 0x00 字符都会被解释为字符串的结束。因此&#xff0c;如果字符串内部包含0x00字符&#xff0c;这实际上会将字符串分…

03、Kerberos安全认证之配置和访问Kerberos安全认证的Hadoop集群学习笔记

文章目录 前言一、Hadoop集群 Kerberos安全配置详细步骤1.1、安装libcrypto.so库1.2、创建HDFS服务用户1.3、配置各服务用户两两节点免密1.4、修改本地目录权限1.5、创建各服务Princial主体1.6、修改Hadoop配置文件1.6.1、配置core-site.xml1.6.2、配置hdfs-site.xml1.6.3、配置…

怎样在 PostgreSQL 中优化对时间序列数据的存储和查询策略?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 《PostgreSQL 中时间序列数据的优化存储与查询策略》 《PostgreSQL 中时间序列数据的优化存储与查询策…