Petalinux 2021.2下my_app自重启更新后服务异常求助
问题分析
你的问题出在原my_app进程直接调用system启动重启脚本时,新启动的my_app继承了原进程的上下文(进程组、文件描述符、会话等),且重启脚本的shell进程未正确退出,导致新进程的运行环境异常。
当my_app自身调用system时,会创建一个sh子进程,这个sh进程属于原my_app的进程组。后续killall -2 my_app发送SIGINT时,不仅原my_app收到信号,这个sh子进程(同进程组)也可能收到信号干扰脚本执行;同时新启动的my_app是该sh进程的子进程,会继承原my_app未关闭的文件描述符(比如监听套接字、日志文件等),导致服务逻辑异常,且sh进程会一直等待新my_app退出才结束,形成残留进程。
而手动启动或先后台运行my_app再执行重启脚本时,重启脚本的sh进程属于独立进程组,新my_app不会继承原进程的异常上下文,因此能正常工作。
解决方案
方案1:用nohup+setsid脱离原进程上下文
修改重启命令,让脚本彻底脱离原进程的会话和进程组,同时关闭不必要的文件描述符:
char* command = "nohup sh -c 'sleep 3; killall -2 my_app; sleep 3; setsid my_app > /dev/null 2>&1' &"; system(command);
nohup:让进程忽略SIGHUP信号,避免原进程退出时被挂起setsid:创建新的会话和进程组,让my_app成为会话首进程,彻底脱离原进程控制> /dev/null 2>&1:重定向标准输出和错误,避免占用原进程终端
方案2:用C代码直接实现重启逻辑(推荐,避免shell依赖)
放弃system调用,手动通过fork+exec实现重启流程,彻底脱离原进程上下文:
#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> void start_restart_process() { pid_t pid = fork(); if (pid < 0) { // 处理fork失败 return; } else if (pid == 0) { // 子进程:再次fork让孙子进程成为孤儿进程,由init/systemd收养 pid_t grand_pid = fork(); if (grand_pid < 0) { _exit(1); } else if (grand_pid == 0) { // 孙子进程:脱离原会话和进程组 setsid(); // 关闭所有继承的文件描述符(按需保留必要的) for (int i = 0; i < getdtablesize(); i++) { close(i); } // 等待原进程退出 sleep(3); // 杀死原my_app进程 system("killall -2 my_app"); // 确保原进程完全退出 while (system("pgrep my_app > /dev/null") == 0) { sleep(0.5); } // 启动新的my_app execl("/usr/bin/my_app", "my_app", NULL); // exec失败则退出 _exit(1); } else { // 子进程直接退出,让孙子进程成为孤儿 _exit(0); } } else { // 父进程等待子进程退出,避免僵尸进程 waitpid(pid, NULL, 0); } }
替换原来的system(command)调用为start_restart_process()即可。
方案3:确保原进程完全退出后再启动新进程
修改重启脚本,增加原进程存活检查,避免新进程与原进程资源冲突:
char* command = "( sleep 3; killall -2 my_app; while pgrep my_app > /dev/null; do sleep 0.5; done; my_app) &"; system(command);
该方案可配合方案1使用,进一步降低资源冲突概率。
验证要点
- 重启后通过
ps -ef | grep my_app查看,my_app的父进程应为init或systemd - 确认无残留的
sh进程 - 通过
lsof -p <my_app_pid>检查新进程的文件描述符是否正常
内容的提问来源于stack exchange,提问作者alexv9
相关产品推荐
相关产品推荐

