【Linux】守护线程自动重启某个程序的3种常用办法

目的:利用守护线程实现程序自启。

1.shell脚本

#!/bin/sh

#添加本地执行路径
export LD_LIBRARY_PATH=./

while true; do
        #启动一个循环,定时检查进程是否存在
        server=`ps aux | grep a.out | grep -v grep`
        if [ ! "$server" ]; then
            #如果不存在就重新启动
            ./a.out
            #启动后沉睡10s
            sleep 1
            echo "reboot"
        fi
        #每次循环沉睡10s
        sleep 2
        echo "this is sleep 5"
done
// g++ test.cpp
#include <iostream>
#include <signal.h> 
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

#include <errno.h>
using namespace std;


int main() {
    while (1) {
        printf("this is me\n");
        sleep(1);
    }
}

 

  • 举个简单的例子:编译以下文件并执行g++ test.cpp,然后./a.out,在终端可看到每隔1s打印一次"this is me"
  • 然后ps aux可看到正在执行的程序a.out的PID 
  • 执行脚本sh .daemon.sh
  • 手动杀死线程kill PID
  • 然后可看到test程序重启,并实时的打印"this is me",达到了通过脚本来重启程序的目的
 

2.查看/proc目录下是否有这个线程

首先要有一个概念,每一个被创建的线程都会放在proc文件夹下,而在proc文件夹的以线程ID命名的文件夹里面都包含有一堆关于这个线程ID的相关信息。而正在执行的程序名字就在/proc/[PID]/status文件夹内。

随便进入proc的某个线程文件夹,然后cat status,即可看到相关信息。操作步骤如下,即可看到这个执行的程序的名字。。

所以思路就是:

1.遍历/proc文件夹下所有的进程ID,然后用fopen去读/proc/[进程ID]/status的文件内容。如果有这个ID,并且读出文件的Name和预期的一样,就证明这个程序存在。

2.当遍历了所有的/proc/[进程ID]/status也没有找到我们想要的这个线程名字(a.out),就用execl("./a.out")重启这个程序。。

参考代码:仅有找到/proc/[PID]/status文件的Name是否与预期结果相同的代码。。。具体操作见代码前面的注释。。

// 在/proc文件下去解析某个程序的运行状态,名字----
// 读/proc/597097/status文件的Name与 ./a.out test的test是否一致
//     execv("/proc/self/exe", exec_argv);  重启程序
// 编译:g++ get_running_program.cpp
// 执行:./a,out test
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <dirent.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
// get pid by program name

int main (int argc, char* argv[])
{
    DIR *pdir = NULL;
    struct dirent *pde = NULL;
    FILE *pf = NULL;
    char buff[128];
    char buff2[128];
    char *pstr = NULL;
    int pid, ppid;
    int n;
    int i;

    pdir = opendir("/proc");
    if (!pdir)
    {
        perror("open /proc fail.\n");
        return -1;
    }

    while ((pde = readdir(pdir))) // 遍历读出目录中的所有线程目录
    {
        if ((pde->d_name[0] < '0')
        || (pde->d_name[0] > '9'))
        {
            continue;
        }
        sprintf(buff, "/proc/%s/status", pde->d_name);
        printf("path = %s\n",buff);
        pf = fopen(buff, "r");
        if (pf)
        {
            n = fread(buff, 1, 127, pf);
            printf("buff = %s\n",buff);
            fclose(pf);
            buff[n] = 0;

            for (i = 0; i < n; i++)
            {
                if ('\n' == buff[i])
                {
                    buff[i] = 0;
                    break;
                }
            }
        printf("== (%s) ==\n", buff);
            n = i; 
            for (i = 0; i < n; i++)
            {
                if ((' ' == buff[i]) || ('\t' == buff[i]))
                {
                    break;
                }
            }

            for (; i < n; i++)
            {
                if ((' ' != buff[i]) && ('\t' != buff[i]))
                {
                    break;
                }
            }

        printf("NAME: (%s)\n", buff + i);

            if (0 == strcmp(buff + i, argv[1]))
            {
                printf("found %s, pid = %d\n", buff + i, atoi(pde->d_name));
                break;
            }
        }
    }

    closedir(pdir);
    return 0;
}

3.通过程序执行终端命令来解析命令的内容

通过终端命令即可看到有没有这个线程,那能不能得到ps出来在终端的内容呢?经查找资料是可以的。。

比如我们的执行程序名为:a.out ,于是调用命令即可看到正在运行的程序

参考代码如下:---然后如果需要PID,或者名字,就需要去网上找一下具体的grep用法,来得到想要的信息。。---参考代码仅解析得到了程序a.ou的线程ID

// 如何调用【linux】shell命令行命令并获取命令行的输出内容

#include <stdio.h>
#include <string.h>
 
void executeCMD(const char *cmd, char *result)
{
    char buf_ps[1024];
    char ps[1024]={0};
    FILE *ptr;
    strcpy(ps, cmd);
    if((ptr=popen(ps, "r"))!=NULL) //执行命令,返回的字符串指针ptr
    {
        while(fgets(buf_ps, 1024, ptr)!=NULL)
        {
//	       可以通过这行来获取shell命令行中的每一行的输出
//	   	   printf("%s", buf_ps);
           strcat(result, buf_ps);
           if(strlen(result)>1024)
               break;
        }
        pclose(ptr);
        ptr = NULL;
    }
    else
    {
        printf("popen %s error\n", ps);
    }
}
 
int main()
{
        char result[1024]={0};
        executeCMD("ps aux | grep ./a.out | awk '{print $2}'", result); // 得到a.out的PID
//      这行是将每一行的输出拼接之后获取到了result字符串中了
        printf("%s", result);
        return 0;
}

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Linux 下,守护进程(daemon)是一在后台运行的进程,它通常在系统启动时自动启动,并在系统关闭时自动关闭。守护进程是一长期运行的进程,它不会和任何终端关联,因此无法接收到用户的输入。 在 Linux 中,守护进程通常通过以下步骤实现: 1. 创建子进程,并让子进程成为新的会话组长和进程组长,与控制终端脱离关系。 2. 关闭所有文件描述符,避免占用系统资源。 3. 在后台运行,并定期执行一些操作(如检查日志、处理任务等)。 下面是一个简单的守护进程的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { pid_t pid, sid; int fd; // 创建子进程 pid = fork(); if (pid < 0) { perror("fork error"); exit(EXIT_FAILURE); } if (pid > 0) { // 父进程退出 exit(EXIT_SUCCESS); } // 子进程成为新的会话组长和进程组长 sid = setsid(); if (sid < 0) { perror("setsid error"); exit(EXIT_FAILURE); } // 关闭所有文件描述符 fd = open("/dev/null", O_RDWR, 0); if (fd < 0) { perror("open error"); exit(EXIT_FAILURE); } dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); if (fd > STDERR_FILENO) { close(fd); } // 在后台运行 while (1) { // 定期执行一些操作 sleep(60); } exit(EXIT_SUCCESS); } ``` 在这个代码示例中,我们首先创建了一个子进程,并让子进程成为新的会话组长和进程组长,然后关闭了所有文件描述符,最后在后台运行,并定期执行一些操作。需要注意的是,在这个示例中,我们将标准输入、输出和错误输出都重定向到了 /dev/null,这样可以避免输出到控制台中,从而确保守护进程在后台运行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值