树莓派通过UDP触发subprocess控制raspistill预热拍照问题咨询
问题核心原因分析
- 第一致命问题:
UDP_listener线程调用t.join()后会进入阻塞状态,直到prime_camera线程执行完毕才会继续处理后续UDP报文。但你调用的raspistill -t 0 -o test.jpg -s命令是长期驻留进程,没有触发信号的情况下永远不会退出,直接导致UDP监听线程彻底卡死,无法响应任何后续请求。 - 第二潜在问题:你没有对
raspistill的进程PID做持久化存储,直接用pkill匹配进程名的方式容错率很低,要是设备上同时跑了多个raspistill进程会出现误杀。 - 第三可选优化点:你当前的实现里没有对
isTakingImage状态做原子性修改,多线程并发操作同一个全局变量的时候可能出现状态不同步的问题。
修复方案
- 删掉
UDP_listener里所有的.join()调用,不要阻塞监听线程:
原有代码里
t.start()后立刻t.join()的逻辑会直接堵死监听链路,启动子线程后不需要等待子线程执行完毕,直接回到监听逻辑处理下一个报文即可。
- 全局存储
prime_camera启动的raspistill进程PID,不要用pkill匹配进程名:
# 全局变量新增 raspistill_pid = None
修改prime_camera逻辑:
def prime_camera(): global raspistill_pid cmd = 'raspistill -t 0 -o test.jpg -s' p1 = Popen(shlex.split(cmd)) raspistill_pid = p1.pid
修改take_image逻辑:
import os import signal def take_image(): global raspistill_pid if raspistill_pid is not None: try: os.kill(raspistill_pid, signal.SIGUSR1) except ProcessLookupError: # 进程已经退出,重置状态 raspistill_pid = None
- 对全局状态
isTakingImage、raspistill_pid的读写操作加锁,避免多线程并发竞争导致的状态异常:
import threading state_lock = threading.Lock() # 所有读写全局状态的地方都先加锁 with state_lock: # 修改/读取 isTakingImage、raspistill_pid 的逻辑
- 可选补充:如果需要在预热失败、拍照完成后通知UDP发送端,可以在子线程执行完对应逻辑后单独给源地址回ACK包,不要在监听线程里处理阻塞逻辑。
内容的提问来源于stack exchange,提问作者Too Long Din't Read
相关产品推荐
相关产品推荐

