Python OpenCV多进程摄像头程序Ubuntu下资源无法释放问题求助
问题根因说明
- 为什么Ubuntu下
terminate()会导致摄像头资源不释放:Linux内核的V4L2摄像头驱动是通过进程上下文管理缓冲区的,multiprocessing.Process.terminate()会向子进程发送SIGTERM信号强制终止进程,子进程用户态的cap.release()、OpenCV资源析构逻辑完全没有执行机会,内核中持有的V4L2缓冲区锁没有被正常释放,就会触发VIDIOC_QBUF: No buffer space available错误,该锁无法通过普通进程操作清除,必须重启系统。 - 为什么注释
terminate()后程序无法退出:主进程收到q按键后就停止从cam_image_queue消费数据,子进程的cam_image_queue.put(img)是阻塞调用,当队列填满后子进程会永久卡在put操作上,永远无法执行到if not msg_queue.empty()的退出判断逻辑,导致进程无法正常终止。
问题1解决方案:保留
cam_process.terminate()调用 修改思路:给子进程留足执行资源释放的时间,发送退出信号后先等子进程主动退出,超时再执行强制终止
修改点:
- 发送退出消息后不要立刻停止消费
cam_image_queue,清空队列避免子进程卡在put操作 - 先调用
join设置超时时间等待子进程主动退出,确认子进程已执行完cap.release()后再决定是否需要terminate()
对应修改代码片段:
import time # 新增导入 # main函数内q按键后的逻辑修改为: if key == ord("q"): msg_queue.put("quit") # 继续消费队列2秒,让子进程不会卡在put操作上 start_wait = time.time() while time.time() - start_wait < 2: if not cam_image_queue.empty(): cam_image_queue.get() # 检查子进程是否已经退出 if cam_process.exitcode is not None: break time.sleep(0.01) break # 后面的终止逻辑调整为先等子进程主动退出 cam_process.join(timeout=3) if cam_process.exitcode is None: # 只有子进程超时未退出才强制终止 cam_process.terminate() cam_process.join()
这种修改下,绝大多数场景子进程都会在超时前主动执行完cap.release()后退出,不会触发强制终止,也就不会出现资源泄漏的问题。
问题2解决方案:不使用
cam_process.terminate()调用 修改思路:彻底解决子进程阻塞问题,让子进程可以正常收到退出信号并主动退出
修改点:
- 给
cam_image_queue设置最大长度,避免队列无限制膨胀 - 子进程使用非阻塞方式put队列,队列满直接丢帧避免永久阻塞,每次循环优先检查退出信号
- 主进程发送退出信号后等待子进程主动退出即可
完整修改后代码:
import multiprocessing import cv2 def cam_loop(cam_image_queue, msg_queue): cap = cv2.VideoCapture(0) while True: # 优先检查退出信号 if not msg_queue.empty(): print("got quit msg") break hello, img = cap.read() if not hello: break # 非阻塞put,队列满就丢帧,不会卡住 try: cam_image_queue.put(img, block=False) except: pass print(f"before cap release, isOpened={cap.isOpened()}") cap.release() print(f"after cap release, isOpened={cap.isOpened()}") def main(): # 给队列设置最大长度,最多存2帧避免溢出 cam_image_queue = multiprocessing.Queue(maxsize=2) msg_queue = multiprocessing.Queue() cam_process = multiprocessing.Process( target=cam_loop, args=(cam_image_queue, msg_queue,), ) print("starting process...") cam_process.start() while True: if not cam_image_queue.empty(): img = cam_image_queue.get() cv2.imshow("from queue", img) key = cv2.waitKey(1) if key == ord("q"): msg_queue.put("quit") break print("closing process...") # 不需要terminate,等待子进程自己退出即可 cam_process.join() print("after cam_process join") cv2.destroyAllWindows() if __name__ == "__main__": main()
原理说明:
子进程每次循环优先检查退出信号,队列满的时候非阻塞put直接丢帧,不会出现永久阻塞的情况,收到退出信号后立刻执行cap.release()释放摄像头资源然后主动退出,主进程只需要等待子进程退出即可,不需要强制终止,完全避免了资源泄漏的问题。
内容的提问来源于stack exchange,提问作者dotw
相关产品推荐
相关产品推荐

