Search code examples
pythonmultithreadingopencvtkinterpython-multithreading

Thread doesn't stopping when i want to stop it


I have a program that displays video in a tkinter window. When i want to close window i stopping video thread. But it doesn't stop. There are four functions:

    def start_video(self):
        if self.video is not None:
            self.video_thread_stopped = False
            try:
                if not self.video_thread.is_alive():
                    self.video_thread = threading.Thread(target=self.video_stream)
                    self.video_thread.start()
            except AttributeError:
                if self.video_thread is None:
                    self.video_thread = threading.Thread(target=self.video_stream)
                    self.video_thread.start()

start_video function starts video thread

    def video_stream(self):
        _, frame = self.video.read()
        str_time = time.time()
        while frame is not None and getattr(self.video_thread, "running", True):
            self.current_frame += 1

            # resize and set image to label
            frame = cv2.resize(frame, self.video_frame_size)
            cv2image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)
            imgtk = ImageTk.PhotoImage(image=Image.fromarray(cv2image))
            self.video_label.config(image=imgtk)
            self.video_label.image = imgtk

            # waiting for frame rate
            while time.time() - str_time < (1 / self.fps):
                pass
            str_time = time.time()

            # reading next frame
            _, frame = self.video.read()
        print("exited from loop")

video_stream is the thread function

    def pause_video(self):
        if self.video_loaded:
            self.video_thread_stopped = True
            if self.video_thread is not None:

                # stop video
                self.video_thread.running = False
                print('before join')
                start_time = time.time()
                while self.video_thread.is_alive():
                    if time.time() - start_time > 1:
                        break
                print("after while")
                self.video_thread.join()
                print('after join')

pause_video has to kill thread and stop streaming video

    def on_window_close(self):
        self.pause_video()
        print("thread stopped")
        self.root.destroy()

on_window_close has to stop thread before closing tk window (I have the following code)

root.protocol("WM_DELETE_WINDOW", w.on_window_close)

So when I start video thread and pressing a close button on the tk window - thread doesn't stop. Here is a terminal output

before join
after while

Can someone help me and tell why it doesn't stop the video_thread. Thanks!


Solution

  • I found the solution. In the start_video method you have to make video_thread daemon:

        def start_video(self):
            if self.video is not None:
                self.video_thread_stopped = False
                try:
                    if not self.video_thread.is_alive():
                        self.video_thread = threading.Thread(target=self.video_stream)
                        self.video_thread.daemon = 1
                        # start audio
                        self.audio_class.start(self.current_frame, self.total_video_frames)
                        # start thread
                        self.video_thread.start()
                except AttributeError:
                    if self.video_thread is None:
                        self.video_thread = threading.Thread(target=self.video_stream)
                        self.video_thread.daemon = 1
                        # start audio
                        self.audio_class.start(self.current_frame, self.total_video_frames)
                        # start thread
                        self.video_thread.start()
    

    And in the pause_video method you need to remove line with video_thread.join()

        def pause_video(self):
            if self.video_loaded:
                self.video_thread_stopped = True
                if self.video_thread is not None:
                    # stop audio
    
                    # stop video
                    self.video_thread.running = False
                    print("video stopped")
                    self.audio_class.stop()
                    print("audio stopped")
                    # print('before join')
                    start_time = time.time()
                    while self.video_thread.is_alive():
                        # print("waiting for none")
                        if time.time() - start_time > 1:
                            # self.video_thread = None
                            break