Python中的死锁

时间:2018-03-07 23:29:48

标签: python multithreading tkinter locking deadlock

我使用tkintercv2编程GUI,使用Thread从计算机相机中提取视频流。为此,Locks使用while循环重新加载图像。

我一直在使用Threads,因此import tkinter as tk import cv2 import time import sys import threading from PIL import ImageTk, Image class Application: gui_root = None gui_panel = None frame = None video_capture = None stop_event = None thread = None thread_lock = None def __init__(self): self.gui_root = tk.Tk() self.gui_root.geometry("640x480") self.gui_root.resizable(False, False) self.video_capture = cv2.VideoCapture(0) self.stop_event = threading.Event() self.thread_lock = threading.Lock() self.thread = threading.Thread(target=self.load_frame, args=()) self.thread.start() self.gui_root.wm_protocol("WM_DELETE_WINDOW", self.on_close) def start(self): self.gui_root.mainloop() def load_frame(self): print('Starting load_frame') while self.thread_lock.acquire() and not self.stop_event.is_set(): _, self.frame = self.video_capture.read() self.frame = cv2.resize(self.frame, (640, 480)) c_image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB) c_image_tk = ImageTk.PhotoImage(Image.fromarray(c_image)) if self.gui_panel is None: self.gui_panel = tk.Label(image=c_image_tk) self.gui_panel.place(width=640, height=480, x=0, y=0) else: self.gui_panel.configure(image=c_image_tk) self.thread_lock.release() print("End of while") self.thread_lock.release() print('End of Process 2') def on_close(self): self.stop_event.set() print("Event set") with self.thread_lock: self.video_capture.release() self.gui_root.destroy() app = Application() app.start() (主要的和辅助的)都按预期结束了他们的流程。但是,由于我无法识别死锁,我无法做到这一点。

代码如下:

flatMap

1 个答案:

答案 0 :(得分:0)

这里最可能出现的问题是你正在尝试从后台线程中创建一个新的tk.Label Tkinter,而且这是不允许的。

我的第一个猜测是,正在发生的事情是后台线程上的Tk代码只是悬挂 - 这实际上并不是一个死锁,但是因为你有一个线程在持有锁的情况下永远挂起,所以没有其他人会永远获得那个锁,所以它的效果大致相同。

解决这个问题的唯一方法是让你的后台线程将消息发布到队列,请求GUI内容为他们完成,并让主线程每次通过事件循环轮询该队列(例如,通过一个after函数。)

旧的mttkinter项目透明地包装了它,但遗憾的是它从未针对现代Python进行更新。几年前,我打了一个快速端口(https://github.com/abarnert/mttkinter),但是我从来没有严格测试过,而且我不知道是否有人曾用它来做任何严肃的事情。

但你可以试试这个至少是为了快速测试。如果它没有任何区别,那么你可能已经排除了Tk线程问题;如果它有所作为,那就太好了(虽然这种差异可能是“现在它没有冻结,但它会在50%的时间内崩溃 - 在这种情况下你没有完成,并且不能相信mttkinter原样,但至少你知道Tk线程是你必须解决的问题。)