展厅播放软件崩了怎么自动拉起?进程守护实操

2026-07-27

「给核心软件装个看门狗」这句话在运维清单里出现过无数次,但很少有人说清楚这玩意儿具体怎么装。本文补上这一段。文中脚本以 Windows 环境为例,路径与进程名请按你的实际情况替换。

做展厅久了会发现一件事:指望软件永远不崩,是不现实的。播放软件跑一个月不出问题算它争气,可展厅是 365 天连轴转,显卡驱动打个嗝、素材文件读到坏扇区、第三方 SDK 内存泄漏,总有一次让它挂掉。

真正能拉开差距的不是”崩不崩”,而是崩了之后多久能自己起来。没有守护,软件半夜两点崩一次,黑屏就一直挂到第二天早上开馆;有守护,十秒钟自己活过来,观众根本不知道发生过什么。

这篇把进程守护从头讲一遍——怎么判断软件”死了”、怎么把它拉起来、怎么避免拉出更大的乱子。

守护到底在守什么

看门狗的活儿说白了就两步循环:判断目标还活着吗 → 不活了就拉起来。难点全在第一步,因为”活着”有三种口径,越往下越准,也越难做。

第一种:进程名还在不在。 最简单,tasklist 一查就知道。问题是它只能发现”进程没了”这一种死法。

第二种:主窗口句柄还在不在。 比进程名进一步。有些软件崩溃后进程还挂着(变成僵尸),但窗口已经没了,画面自然也没了。查窗口句柄能抓到这一类。

第三种:窗口还响应吗。 最准。程序卡死(无响应白屏)时,进程在、窗口也在,但已经不干活了。这种要靠给窗口发消息看是否超时来判断。

现场怎么选?绝大多数情况下,进程名 + 窗口句柄这两条就够用了,能覆盖八九成的崩溃。第三种”响应性检测”实现复杂,还容易误判——软件正在加载大素材时本来就会短暂无响应,判错了反而把好好的程序杀掉重启,得不偿失。

先动手:一个最简守护脚本

理解了原理,先用十行脚本跑通一遍。新建 guard.ps1

$exe  = 'D:\Player\player.exe'
$name = [System.IO.Path]::GetFileNameWithoutExtension($exe)

while ($true) {
    if (-not (Get-Process -Name $name -ErrorAction SilentlyContinue)) {
        Write-Host "$(Get-Date -f 'HH:mm:ss') 进程不在,拉起"
        Start-Process $exe
    }
    Start-Sleep -Seconds 10
}

用批处理也行,逻辑一样:

@echo off
:loop
tasklist /fi "imagename eq player.exe" | find /i "player.exe" >nul
if errorlevel 1 start "" "D:\Player\player.exe"
timeout /t 10 /nobreak >nul
goto loop

你应该看到——脚本跑起来后,去任务管理器把 player.exe 结束掉,十秒内它自己又出现了。这就是守护最核心的那点东西,不神秘。

把这个脚本本身加进开机自启(做法见展厅播放设备开机自启与断电恢复设置),一台机的基础守护就成了。

裸重启的坑:重启风暴

上面那个脚本能用,但不能直接拿去上生产。因为它有个致命问题:如果软件是因为”必然失败”的原因起不来——素材盘没挂上、授权过期、配置文件损坏——那它会每隔十秒重启一次,一晚上拉起几千次。

后果不只是日志被刷爆。反复拉起会疯狂占 CPU、疯狂写盘,严重时把机器拖到连远程桌面都连不上,你连救都救不回来,只能第二天跑现场。这叫重启风暴,是自制看门狗最常见的翻车方式。

躲开它要加两道闸:

第一道,指数退避。 别每次都等固定十秒。第一次崩了等 5 秒拉,还崩就等 10 秒、20 秒、40 秒……逐次翻倍,直到某个上限(比如 5 分钟)封顶。这样偶发崩溃能秒恢复,而”必然失败”的情况会自动降频,不至于把机器拖死。

第二道,时间窗限次。 设一个规则:10 分钟内最多拉起 5 次,超了就停手,别再试了,同时把这个状态记下来报给运维。因为连续崩 5 次说明这不是偶发问题,机器自己解决不了,需要人介入。守护的职责是扛偶发故障,不是硬扛配置错误。

改进后的核心逻辑长这样:

$delay = 5           # 当前退避秒数
$max   = 300         # 退避上限 5 分钟
$fails = @()         # 最近失败时间戳

while ($true) {
    if (-not (Get-Process -Name $name -ErrorAction SilentlyContinue)) {
        # 清掉 10 分钟以前的记录,只看时间窗内的
        $fails = @($fails | Where-Object { $_ -gt (Get-Date).AddMinutes(-10) })
        if ($fails.Count -ge 5) {
            Write-Host "10 分钟内已拉起 5 次,停止重试,等待人工处理"
            Start-Sleep -Seconds 600
            $fails = @(); $delay = 5
            continue
        }
        Start-Sleep -Seconds $delay
        Start-Process $exe
        $fails += (Get-Date)
        $delay = [Math]::Min($delay * 2, $max)   # 翻倍,封顶
    } else {
        $delay = 5    # 恢复正常就把退避重置
    }
    Start-Sleep -Seconds 10
}

这两道闸是自制看门狗和能用的看门狗之间的分界线。如果你只从这篇文章带走一件事,就带走这个。

三条落地路线怎么选

守护逻辑想明白了,落地有三条路,各有各的适用面。

方式好在哪代价适合
Windows 任务计划系统自带,不装东西只能定时轮询,退避限次得自己在脚本里写;会话/权限坑多单台、临时、能接受粗糙
自己写脚本完全可控,想加什么加什么退避、限次、日志、自启、自身被杀了谁管,全得自己兜有开发能力、场景特殊
现成代理软件装上配一下就行,坑别人替你踩过了得接受它的配置方式多台点位、要统一管

第二条路有个容易被忽略的问题:守护脚本自己崩了谁来守护? 一个 PowerShell 窗口被人误关、或者脚本自身抛异常退出,整套守护就静默失效了,而你完全不知道——直到某天软件崩了没起来。成熟做法是双进程互相保活:两个进程互相盯着对方,谁没了另一个把它拉起来。这东西自己写起来不难,但要写对(避免互相拉起打架、避免同时挂掉)需要花点心思。

第三条路就是省掉这些。我们自研的 SoftAgent 走的是这条:装在被控电脑上,在界面里填程序路径、勾上守护开关就行,崩溃自愈带指数退避 + 时间窗限次(就是上面讲的那两道闸),自身是双进程互相保活。免费版可以守 2 个程序,展厅现场典型就是”播放软件 + 中控客户端”两个关键进程,通常够用。每项还能单独设启动延迟,用来做开机错峰——先起 A,隔十秒再起 B。

配好之后一定要验一遍

守护这东西最怕”配了但没生效”,上线前务必实测:

  • 杀进程测试:任务管理器结束目标进程,掐表看多久自恢复;
  • 重启测试:重启机器,确认守护自身也跟着自启了(这一步最常漏);
  • 风暴测试:把目标程序改个名让它必然起不来,观察是否在若干次后停手,而不是无限重试;
  • 误杀测试:确认软件正常加载大素材时不会被守护判死后杀掉。

第二条特别容易栽——守护配得好好的,结果它自己没设开机自启,机器一重启守护就没了,等于裸奔。

常见症状对照

症状多半原因怎么办
软件崩了不恢复守护没跑,或没设自启确认守护进程在,且自身已加开机自启
一晚上重启几千次没有退避和限次加指数退避 + 时间窗限次
进程在但画面黑只查了进程名,僵尸进程没抓到改查窗口句柄
加载大素材时被重启用了响应性检测且超时设太短放宽超时,或退回句柄判活
守护和自启抢着拉起,开了两个实例两套机制重复启动二选一,或给程序加单实例互斥
拉起来了但没全屏拉起的是程序本身,没恢复播放态让程序自身支持启动即全屏播放

最后一条值得多说一句:守护只负责把程序拉起来,拉起来之后能不能自动回到播放状态,取决于程序自己。所以选播控软件时要确认它支持”启动即自动加载片源并全屏”,具体配置见展厅设备开机自动全屏播放配置

小结

进程守护的核心就三句话:判活优先用进程名 + 窗口句柄,重启必须带退避和限次,守护自己也得有人守

它在整个无人值守体系里的位置是”最后一道保险”——定时和自启保证展厅能自己开起来,守护保证开起来之后一直不掉链子。三件套的全貌可以看展厅无人值守怎么做;如果现在正卡在”软件根本起不来”,那先按设备开机/自启失败 8 步排查清单把地基修好,再回来加守护。

需要展厅软硬件方案或定制开发?