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

PHP中clamscan扫描部分路径后无法终止cpulimit的问题

问题描述

通过PHP切换到Linux指定用户后,执行以下操作:

  • 用cpulimit将clamscan的CPU使用率限制在88%,后台运行
  • 递归扫描指定路径(如/home/user、/home/user/mail),扫描日志写入指定文件,扫描完成后终止cpulimit,同样后台运行

两段exec命令均加&后台执行,但出现异常:

  • 扫描/home/user时,扫描结束后cpulimit仍在运行,通过ps aux | grep cpulimit可查到进程
  • 扫描/home/user/mail或/home/user/public_html时,扫描结束后cpulimit能正常终止

相关PHP代码:

switch_user($user);
exec('cpulimit -l 88 -e clamscan &');
exec('clamscan --recursive '.$scan_path.' -l '.$log_file.' 2>&1 && pkill cpulimit &');
问题原因

原代码依赖进程名匹配(cpulimit -e clamscan、pkill cpulimit),存在以下隐患:

  1. 当扫描大目录(如/home/user)时,clamscan可能衍生子进程,cpulimit会持续监控所有名为clamscan的进程,即使主进程结束,若有残留子进程或进程名缓存,cpulimit不会自动退出
  2. pkill cpulimit会终止当前用户下所有cpulimit进程,但若扫描大目录时,clamscan的退出信号未正确触发&&后的pkill(如进程组差异、后台会话隔离),会导致cpulimit残留
解决方案

改用PID绑定的方式,让cpulimit仅监控当前启动的clamscan进程,扫描结束后仅终止对应cpulimit进程,避免进程名匹配的不确定性。

修改后的PHP代码:

switch_user($user);
// 将clamscan启动、cpulimit绑定、扫描结束后终止cpulimit的逻辑整合为一个后台命令
exec('(
    clamscan --recursive '.$scan_path.' -l '.$log_file.' 2>&1 & 
    CLAMSCAN_PID=$!; 
    cpulimit -l 88 -p $CLAMSCAN_PID & 
    CPULIMIT_PID=$!; 
    wait $CLAMSCAN_PID; 
    kill $CPULIMIT_PID
) &');

代码说明

  1. 用子shell()包裹所有命令,确保进程在同一会话内运行
  2. 启动clamscan后立即记录其PID(CLAMSCAN_PID=$!)
  3. 针对该PID启动cpulimit,并记录cpulimit的PID
  4. 通过wait等待clamscan扫描完成,再用kill终止对应的cpulimit进程
  5. 整个逻辑后台运行(末尾&)

这种方式彻底避免了进程名匹配的问题,无论扫描路径大小,都能确保cpulimit在clamscan结束后被精准终止。

内容的提问来源于stack exchange,提问作者jay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:01:33