首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python中的DeadLock

Python中的DeadLock
EN

Stack Overflow用户
提问于 2018-03-07 23:29:47
回答 1查看 1.7K关注 0票数 0

我正在用tkinter编写一个图形用户界面,它使用cv2从计算机摄像机中提取视频流。为此,Thread使用while循环重新加载映像。

我一直在使用Locks,所以Threads (主Threads和auxiliar)都按照预期结束了它们的过程。但是,由于一个无法识别的DeadLock,我无法做到这一点。

守则如下:

代码语言:javascript
复制
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()
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-08 00:38:15

这里最可能的问题是,您试图从后台线程创建一个新的tk.Label,这是不允许的。

我的第一个猜测是后台线程上的Tk代码只是挂起的--这并不是真正的死锁,但是既然在持有锁的时候会永远挂起一个线程,那么没有其他人会获得这个锁,所以它的效果几乎是一样的。

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

旧的mttkinter项目以透明的方式结束了这个过程,但不幸的是,它从未为现代Python进行过更新。几年前,我组装了一个快速端口(在https://github.com/abarnert/mttkinter),但是我从来没有对它进行严格的测试,我也不知道是否有人用它来做任何严肃的事情。

但你可以试试这个,至少是为了一个快速的测试。如果这没有什么区别,那么您可能已经排除了Tk线程问题;如果它产生了很大的影响,那么很好(尽管这种区别可能是“现在它没有冻结,但是它崩溃了50%的时间--在这种情况下,您没有完成任务,并且不能相信mttkinter的原样,但至少您知道Tk线程是您必须解决的问题)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49162990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档