一个简单高效的 C++ 监控程序,带有一个通用的 Makefile

大家好!我是大聪明-PLUS
尽管语言模型已经发展成熟,但我认为我设计的监督程序版本或许足够有趣,值得写成一篇文章。该监督程序的作用是重启因某种原因崩溃并报错的程序。此外,如果程序在没有报错的情况下退出,则不会重启,也不会生成任何日志。日志会记录崩溃时间和错误类型。通用的 Makefile 文件可能很有用,因为它只需要放在源代码目录中,并添加必要的路径即可,例如:
LDFLAGS = -I/usr/include/boost
LIBS = -lboost_serialization

本文的主题并不新颖,但或许对某些人有用。文章主要关注后端,因为后端运行的连续性更为重要。值得注意的是,C++ 本身已经是一种相当健壮的编程语言。问题在于,教育机构通常先教授 C 语言,再教授 C++,而且 C++ 的编码风格往往是带有类的 C 语言。这自然导致了人们对 C++ 健壮性不足的印象。随着语言模型的出现,C++ 代码的健壮性已显著提高。我在生成的代码中没有遇到任何内存错误,逻辑错误虽然常见,但代码本身却堪称典范。
基础代码相对较小;我决定不添加过多的功能。主线程留空以便于自定义,被监控的程序则运行在单独的线程中。
直接主管代码

复制代码
#include <iostream>`
`#include <thread>`
`#include <atomic>`
`#include <unistd.h>`
`#include <sys/wait.h>`
`#include <fcntl.h>`
`#include <csignal>`
`#include <fstream>`
`#include <ctime>`
`#include <string>`
`#include <iomanip>`
`#include <sstream>`
`#include <condition_variable>`
`#include <mutex>`


`std::string` `getCurrentDateTime`() {
    `// `
    `std::time_t` `now` `=` `std::time`(`nullptr`);
    `std::tm*` `timeInfo` `=` `std::localtime`(`&now`);

    `// `
    `std::ostringstream` `oss`;
    `oss` `<<` `std::put_time`(`timeInfo`, `"%Y-%m-%d %H:%M:%S"`);

    `return` `oss`.`str`();  `// `
}

`std::ofstream` `createLogfile`() {
    `// `
    `std::time_t` `now` `=` `std::time`(`nullptr`);
    `std::tm*` `timeInfo` `=` `std::localtime`(`&now`);

    `// `
    `std::ostringstream` `oss`;
    `oss` `<<` `std::put_time`(`timeInfo`, `"%Y-%m-%d_%H-%M-%S"`);

    `std::string` `timestamp` `=` `oss`.`str`();
    `std::string` `filename` `=` `"logfile_"` `+` `timestamp` `+` `".txt"`;

    `// `
    `std::ofstream` `logFile`(`filename`);

    `if` (`logFile`.`is_open`()) {
    } `else` {
        `std::cerr` `<<` `""` `<<` `std::endl`;
    }

    `return` `logFile`; `// `
}

`int` `runApp`(`const` `std::string&` `program`, `int` `maxRestarts`, `std::atomic<bool>&` `shouldExit`, `std::condition_variable` `&cv`) {
    `int` `restartCount` `=` `0`;
	 `int` `status` `=` `0`;
		`std::ofstream` `log`;
		`bool` `log_is_created=false`;
    `while` (`restartCount` `<` `maxRestarts`) {
        `pid_t` `pid` `=` `fork`();
        `if` (`pid` `==` `0`) {
            `// `
            `execl`(`program`.`c_str`(), `program`.`c_str`(), `nullptr`);
            `perror`(`"execl"`);
            `exit`(`EXIT_FAILURE`);
        } `else` `if` (`pid` `<` `0`) {
            `perror`(`"fork"`);
            `exit`(`EXIT_FAILURE`);
        } `else` {
            `// `
            `waitpid`(`pid`, `&status`, `0`);
            `if` (`WIFEXITED`(`status`)) {
                `std::cerr` `<<` `"Program exited with status "` `<<` `WEXITSTATUS`(`status`) `<<` `std::endl`;
                `shouldExit` `=` `true`;
				`cv`.`notify_all`();
                `return` `0`;
            } `else` `if` (`WIFSIGNALED`(`status`)) {
            	`int` `sig=WTERMSIG`(`status`);
                `std::cerr` `<<` `"Program was killed by signal "` `<<` `sig` `<<` `std::endl`;
				 `switch` (`sig`) {
        `case` `SIGSEGV`:
            `std::cout` `<<` `"Segmentation fault"` `<<` `std::endl`;
            `break`;
        `case` `SIGABRT`:
            `std::cout` `<<` `"Aborted"` `<<` `std::endl`;
            `break`;
        `case` `SIGFPE`:
            `std::cout` `<<` `"Floating point exception"` `<<` `std::endl`;
            `break`;
        `case` `SIGILL`:
            `std::cout` `<<` `"Illegal instruction"` `<<` `std::endl`;
            `break`;
        `case` `SIGINT`:
            `std::cout` `<<` `"Interrupted by user (Ctrl+C)"` `<<` `std::endl`;
            `break`;
        `case` `SIGTERM`:
            `std::cout` `<<` `"Termination signal received"` `<<` `std::endl`;
            `break`;
        `default`:
            `std::cout` `<<` `"Unknown signal."` `<<` `std::endl`;
    	}
    	`if`(`log_is_created==false`) {`log` `=` `createLogfile`();`log_is_created=true`;}
	 	`if` (`log`.`is_open`())
	 	{
			`log<<getCurrentDateTime`();
			`switch` (`sig`) {
        `case` `SIGSEGV`:
            `log` `<<` `" Segmentation fault"` `<<` `std::endl`;
            `break`;
        `case` `SIGABRT`:
            `log` `<<` `" Aborted"` `<<` `std::endl`;
            `break`;
        `case` `SIGFPE`:
            `log` `<<` `" Floating point exception"` `<<` `std::endl`;
            `break`;
        `case` `SIGILL`:
            `log` `<<` `" Illegal instruction"` `<<` `std::endl`;
            `break`;
        `case` `SIGINT`:
            `log` `<<` `" Interrupted by user (Ctrl+C)"` `<<` `std::endl`;
            `break`;
        `case` `SIGTERM`:
            `log` `<<` `" Termination signal received"` `<<` `std::endl`;
            `break`;
        `default`:
            `log` `<<` `" Unknown signal."` `<<` `std::endl`;
    	}
			
		}
		`log`.`close`();
    }
        `restartCount++`;
        `std::cout` `<<` `"Restart count: "` `<<` `restartCount` `<<` `"/"` `<<` `maxRestarts` `<<` `std::endl`;
        }
    }

    `if` (`restartCount` `>=` `maxRestarts`) {
        `std::cerr` `<<` `"Max restarts reached. Exiting."` `<<` `std::endl`;
        `shouldExit` `=` `true`; `// `
		`cv`.`notify_all`();
    }
    `return` `0`;
}

`int` `main`(`int` `argc`, `char*` `argv`[]) {
    `if` (`argc` `!=` `3`) {
        `std::cerr` `<<` `"Usage: "` `<<` `argv`[`0`] `<<` `" <program> <max_restarts>"` `<<` `std::endl`;
        `return` `EXIT_FAILURE`;
    }

    `std::string` `program` `=` `argv`[`1`];
    `int` `maxRestarts` `=` `std::stoi`(`argv`[`2`]);

    `// `
    `std::atomic<bool>` `shouldExit`(`false`);
	`std::mutex` `mtx`;
	`std::condition_variable` `cv`;

    `try` {
        `std::thread` `appThread`(`runApp`, `program`, `maxRestarts`, `std::ref`(`shouldExit`), `std::ref`(`cv`));
        `appThread`.`detach`();
    } `catch` (`const` `std::system_error&` `e`) {
        `std::cerr` `<<` `"Failed to create thread: "` `<<` `e`.`what`() `<<` `std::endl`;
        `return` `EXIT_FAILURE`;
    }

    `// `
    `//`
    `//    `
    `//`
	`std::unique_lock<std::mutex>` `lock`(`mtx`);
    `while` (`!shouldExit`.`load`()) {
        `cv`.`wait`(`lock`);  `// `
    }

    `std::cout` `<<` `"Main thread exiting."` `<<` `std::endl`;
    `return` `0`;
}
`

接下来,我们来看通用(或部分通用)的 Makefile。它并非其他构建系统的直接竞争对手;它可以用于中小型项目、快速原型开发以及测试生成的 LLM 代码。例如,一个文件夹包含多个源文件(.cpp 和 .h 文件)。这可能是一个包含测试的小型项目。Makefile 会识别包含"int main"的文件。这些文件用于创建可执行文件。其余的 .cpp 文件用于创建目标文件,这些目标文件存储在 obj 文件夹中。是的,"int main"有可能出现在注释或字符串中。使用正则表达式是为了确保测试源文件可以编译在同一文件夹中;否则,将会出现 main 函数重复的错误。
Makefile 代码

复制代码
CXX` `=` `g++`
`CXXFLAGS` `=` `-Wall` `-Wextra` `-std=c++2a` `-O2` `-s` `-fdata-sections` `-ffunction-sections` `-flto`
`LDFLAGS` `=` `-I/usr/include/boost`
`LIBS` `=` `-lboost_serialization`

`# `
`SRCS` `=` `$`(`wildcard` `*`.`cpp`)

`# `
`MAIN_SRCS` `=` `$`(`shell` `grep` `-l` `"^\s*int\s\+main\s*"` `$`(`SRCS`))
`MAIN_EXES` `=` `$`(`MAIN_SRCS:`.`cpp=`)

`# `
`OTHER_SRCS` `=` `$`(`filter-out` `$`(`MAIN_SRCS`),`$`(`SRCS`))
`OTHER_OBJS` `=` `$`(`patsubst` `%`.`cpp`, `obj/%`.`o`, `$`(`OTHER_SRCS`))
`MAIN_OBJS` `=` `$`(`patsubst` `%`.`cpp`, `obj/%`.`o`, `$`(`MAIN_SRCS`))

`# `
`all:` `obj` `$`(`OTHER_OBJS`) `$`(`MAIN_OBJS`) `$`(`MAIN_EXES`)
	`@for` `dir` `in` `*/` ; `do` \
		`if` [ `"$$dir"` `!=` `"obj/"` ] `&&` [ `"$$dir"` `!=` `"*/"` ] `&&` [ `-f` `"$$dir/Makefile"` ]; `then` \
			`echo` `""`; \
			`$`(`MAKE`) `-C` `"$${dir%*/}"`; \
		`elif` [ `"$$dir"` `!=` `"obj/"` ] `&&` [ `"$$dir"` `!=` `"*/"` ]; `then` \
			`echo` `""`; \
		`fi`; \
	`done`

`# `
`obj:`
	`mkdir` `-p` `obj`

`# `
`obj/%`.`o:` `%`.`cpp`
	`$`(`CXX`) `$`(`CXXFLAGS`) `-MMD` `-MP` `-c` `-o` `$@` `$<`

`# `
`# `
`# `
`%:` `obj/%`.`o` `$`(`OTHER_OBJS`)
	`@echo` `"Linking $@"`
	`$`(`CXX`) `-o` `$@` `$<` `$`(`OTHER_OBJS`) `$`(`LDFLAGS`) `$`(`LIBS`)

`# `
`-include` `$`(`OTHER_OBJS:`.`o=`.`d`) `$`(`MAIN_OBJS:`.`o=`.`d`)

`# `
`clean:`
	`rm` `-rf` `obj` `$`(`MAIN_EXES`)
	`@echo` `""`
	`@for` `dir` `in` `*/` ; `do` \
		`if` [ `"$$dir"` `!=` `"obj/"` ] `&&` [ `"$$dir"` `!=` `"*/"` ] `&&` [ `-f` `"$$dir/Makefile"` ]; `then` \
			`echo` `""`; \
			`$`(`MAKE`) `-C` `"$${dir%*/}"` `clean`; \
		`elif` [ `"$$dir"` `!=` `"obj/"` ] `&&` [ `"$$dir"` `!=` `"*/"` ]; `then` \
			`echo` `""`; \
		`fi`; \
	`done`

.`PHONY:` `all` `clean`
`
相关推荐
烤鱼骑不快1 天前
ubuntu系统安装以及设置
linux·数据库·ubuntu
HIT_Weston1 天前
89、【Ubuntu】【Hugo】搭建私人博客:侧边导航栏(三)
linux·运维·ubuntu
白驹过隙^^1 天前
windows通过docker compose部署oktopus服务
linux·windows·tcp/ip·docker·容器·开源
独自破碎E1 天前
在Linux系统中怎么排查文件占用问题?
linux·运维·服务器
tiechui19941 天前
最小化安装 ubuntu
linux·运维·ubuntu
Maggie_ssss_supp1 天前
Linux-Web服务(Apache)
linux·运维·apache
扶尔魔ocy1 天前
【linux C】在mysql中增加自定义的C动态库
linux·运维·mysql
oMcLin1 天前
如何在Ubuntu 20.04上通过配置ZFS存储池,提升高性能存储系统的可靠性与扩展性
linux·运维·ubuntu
独自破碎E1 天前
使用Linux的top命令进行性能监控的步骤?
linux