You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:27:44