多线程Lock使用正确性咨询:三台相机同步抓拍场景
让我来帮你分析一下代码里的Lock使用情况,以及可以优化的地方:
你的Lock使用正确性分析
先拆解代码里的4处Lock操作:3个WebcamVideoStream实例各自的read_lock,加上主程序里的mainer_lock。
1. 每个相机实例的read_lock:使用完全正确
每个WebcamVideoStream类里的read_lock作用是保护self.frame和self.grabbed这两个共享变量:
update线程在更新帧数据时加锁,确保写入操作是原子性的,不会出现一半是旧帧、一半是新帧的错乱数据;read方法读取并复制帧时加锁,保证读取过程中帧数据不会被修改。
这种每个实例独立锁的设计,既保证了线程安全,又不会互相阻塞不同相机的操作,是多线程处理相机流的标准正确做法。
2. 主程序里的mainer_lock:当前场景下多余,但使用本身无错误
你在按下按键保存图像时加了这个锁,但仔细看这段逻辑:
mainer_lock.acquire() cv2.imwrite('cam_pics/frame.jpg', frame) cv2.imwrite('cam_pics/frame2.jpg', frame2) cv2.imwrite('cam_pics/frame3.jpg', frame3) mainer_lock.release()
这里的frame、frame2、frame3已经是从read()方法获取的副本(read里做了frame = self.frame.copy()),属于主线程独有的变量,不存在其他线程修改它们的可能。所以这个锁在这里是多余的,直接去掉也不会有问题。
当然,如果后续你扩展代码,比如新增其他线程也执行保存操作,这个锁就有存在的必要了,但当前代码场景下不需要。
额外优化建议:实现真正的同步抓拍
当前代码里的frame = vs.read()、frame2 = vs2.read()、frame3 = vs3.read()是依次执行的,这三个帧其实不是严格同一时刻的(因为每个相机的update线程在持续更新帧)。如果需要严格同步的抓拍结果,可以给每个相机实例加一个抓拍触发机制,比如:
import time from threading import Thread, Lock, Event import cv2 class WebcamVideoStream : def __init__(self, src = 0, width = 1024, height = 768) : self.stream = cv2.VideoCapture(src) self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, width) self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, height) (self.grabbed, self.frame) = self.stream.read() self.started = False self.read_lock = Lock() # 新增同步抓拍相关的锁和事件 self.capture_event = Event() self.captured_frame = None def start(self) : if self.started : print("already started!!") return None self.started = True self.thread = Thread(target=self.update, args=()) self.thread.start() return self def update(self) : while self.started : (grabbed, frame) = self.stream.read() self.read_lock.acquire() self.grabbed, self.frame = grabbed, frame self.read_lock.release() # 检查是否需要同步抓拍 if self.capture_event.is_set(): self.captured_frame = frame.copy() self.capture_event.clear() time.sleep(0.01) # 降低CPU占用 def read(self) : self.read_lock.acquire() frame = self.frame.copy() self.read_lock.release() return frame def trigger_capture(self): self.capture_event.set() def get_captured_frame(self): return self.captured_frame.copy() if self.captured_frame is not None else None def stop(self) : self.started = False self.thread.join() def __exit__(self, exc_type, exc_value, traceback) : self.stream.release() if __name__ == "__main__" : vs = WebcamVideoStream(src = 0).start() vs2 = WebcamVideoStream(src = 1).start() vs3 = WebcamVideoStream(src = 2).start() while True : frame = vs.read() frame2 = vs2.read() frame3 = vs3.read() cv2.imshow('webcam', frame) cv2.imshow('webcam2', frame2) cv2.imshow('webcam3', frame3) key = cv2.waitKey(1) if key == 99: # 触发所有相机同步抓拍 vs.trigger_capture() vs2.trigger_capture() vs3.trigger_capture() # 等待抓拍完成(简单实现,可根据实际调整等待时间) time.sleep(0.05) # 获取同步抓拍的帧 cap_frame = vs.get_captured_frame() cap_frame2 = vs2.get_captured_frame() cap_frame3 = vs3.get_captured_frame() if all([cap_frame, cap_frame2, cap_frame3]): cv2.imwrite('cam_pics/frame.jpg', cap_frame) cv2.imwrite('cam_pics/frame2.jpg', cap_frame2) cv2.imwrite('cam_pics/frame3.jpg', cap_frame3) vs.stop() vs2.stop() vs3.stop() cv2.destroyAllWindows() break
内容的提问来源于stack exchange,提问作者BhanuKiran
相关产品推荐
相关产品推荐

