【问题标题】:Threaded application does not stop with keyboard interrupt Python线程应用程序不会因键盘中断 Python 而停止
【发布时间】:2021-06-27 12:31:02
【问题描述】:

我想用键盘中断来停止线程化的 python 应用程序。一个线程捕获图像并将它们放入队列中,另一个线程将图像保存到硬盘。

代码在这里

import numpy as np
import threading
import time
from multiprocessing import Queue
import cv2
from datetime import datetime
import os
#import matplotlib.pyplot as plt
import sys


frames = Queue(50)
exitProgram = False
saveImages = True


class ImageGrabber(threading.Thread):
    def __init__(self, ID):
        threading.Thread.__init__(self)
        self.ID=ID
        self.cam=cv2.VideoCapture(ID)
        self.fps = self.cam.get(cv2.CAP_PROP_FPS)
        self.w=self.cam.get(cv2.CAP_PROP_FRAME_WIDTH)
        self.h=self.cam.get(cv2.CAP_PROP_FRAME_HEIGHT)
        (self.grabbed, self.frame) =self.cam.read()
        cv2.imwrite("testImage.png",self.frame)
        print(f"Camera Opened with fps {self.fps}, width = {self.w}, and height = {self.h}")     
        
        self.stopped = False
        # self.adjustB = adjustBrightness(0.75)  

        
    
    def run(self):
        global frames
        global exitProgram
        while not self.stopped:
            if not self.grabbed or exitProgram is True:
                print("Exit Command reached")
                self.stop()
                self.cam.release()
            else:
                (self.grabbed, self.frame) =self.cam.read()               
                frames.put(self.frame)
                
                
    def stop(self):
        self.stopped = True


class imageSaveThread(threading.Thread):
    def __init__(self,grabber,filePath):
         
        threading.Thread.__init__(self)
        global saveImages
        self.dateTime = self.getDateStamp()
        self.imgName = filePath + 'img_' + self.dateTime + '_'
        self.cntr = 0        
        
    def getDateStamp(self):    
        filedate = str(datetime.now())
        filedate = filedate[0:-7]
        filedate = filedate.replace(':', '_')
        filename = filedate 
        return filename

    def run(self):
        global frames
        while True:
            if(not frames.empty()):
                self.Currframe=frames.get()
                cv2.imwrite(self.imgName + str(self.cntr).zfill(6) + '.png',self.Currframe)
                self.cntr = self.cntr + 1
                print(f"Queue Size in writing = {frames.qsize()} and fram number = {self.cntr}")
            elif exitProgram is True:
                print("Exit Command imageSaveThread reached")
                print(f"Final Queue Size at exit = {frames.qsize()}")
                break         
      

def main():
    if saveImages == True:
        savefilePath = 'D:/111/'
        grabber = ImageGrabber(0)
        imageSaveThr = imageSaveThread(grabber,savefilePath)        
        grabber.start()
        imageSaveThr.start()
        e = threading.Event()
        # imageSaveThread.join()
        # grabber.join()
        print ('Press CTRL-C to interrupt')
        while grabber.isAlive():
            try: 
                time.sleep(5) #wait 1 second, then go back and ask if thread is still alive
            except KeyboardInterrupt: #if ctrl-C is pressed within that second,
                                      #catch the KeyboardInterrupt exception
                e.set() #set the flag that will kill the thread when it has finished
                exitProgram=True
                print ('Exiting...')
                grabber.join()
                imageSaveThr.join()
          
    else:
        videoCodec = 'h264'
        videoExt = 'mkv'
    
if __name__ == '__main__':
    main()

我替换了main函数并直接调用程序然后它工作并像下面的代码一样退出线程

import numpy as np
import threading
import time
from multiprocessing import Queue
import cv2
from datetime import datetime
import os
#import matplotlib.pyplot as plt
import sys


frames = Queue(50)
exitProgram = False
saveImages = True


class ImageGrabber(threading.Thread):
    def __init__(self, ID):
        threading.Thread.__init__(self)
        self.ID=ID
        self.cam=cv2.VideoCapture(ID)
        self.fps = self.cam.get(cv2.CAP_PROP_FPS)
        self.w=self.cam.get(cv2.CAP_PROP_FRAME_WIDTH)
        self.h=self.cam.get(cv2.CAP_PROP_FRAME_HEIGHT)
        (self.grabbed, self.frame) =self.cam.read()
        cv2.imwrite("testImage.png",self.frame)
        print(f"Camera Opened with fps {self.fps}, width = {self.w}, and height = {self.h}")     
        
        self.stopped = False
        # self.adjustB = adjustBrightness(0.75)  

        
    
    def run(self):
        global frames
        global exitProgram
        while not self.stopped:
            if not self.grabbed or exitProgram is True:
                print("Exit Command reached")
                self.stop()
                self.cam.release()
            else:
                (self.grabbed, self.frame) =self.cam.read()               
                frames.put(self.frame)
                
                
    def stop(self):
        self.stopped = True


class imageSaveThread(threading.Thread):
    def __init__(self,grabber,filePath):
         
        threading.Thread.__init__(self)
        global saveImages
        self.dateTime = self.getDateStamp()
        self.imgName = filePath + 'img_' + self.dateTime + '_'
        self.cntr = 0        
        
    def getDateStamp(self):    
        filedate = str(datetime.now())
        filedate = filedate[0:-7]
        filedate = filedate.replace(':', '_')
        filename = filedate 
        return filename

    def run(self):
        global frames
        while True:
            if(not frames.empty()):
                self.Currframe=frames.get()
                cv2.imwrite(self.imgName + str(self.cntr).zfill(6) + '.png',self.Currframe)
                self.cntr = self.cntr + 1
                print(f"Queue Size in writing = {frames.qsize()} and fram number = {self.cntr}")
            elif exitProgram is True:
                print("Exit Command imageSaveThread reached")
                print(f"Final Queue Size at exit = {frames.qsize()}")
                break         
      

savefilePath = 'D:/111/'
grabber = ImageGrabber(0)
imageSaveThr = imageSaveThread(grabber,savefilePath)        
grabber.start()
imageSaveThr.start()
e = threading.Event()
# imageSaveThread.join()
# grabber.join()
print ('Press CTRL-C to interrupt')
while grabber.isAlive():
    try: 
        time.sleep(5) #wait 1 second, then go back and ask if thread is still alive
    except KeyboardInterrupt: #if ctrl-C is pressed within that second,
                              #catch the KeyboardInterrupt exception
        e.set() #set the flag that will kill the thread when it has finished
        exitProgram=True
        print ('Exiting...')
        grabber.join()
        imageSaveThr.join()

我无法理解原因。谁能告诉我是什么原因?

【问题讨论】:

  • 如果变量位于函数中任何位置的赋值左侧,则该变量是该函数的局部变量(如果未另行声明)并且可能会隐藏同名的全局变量(可以'然后在这个函数中修改)。
  • 如果您在谈论exitProgram 变量,现在我将其更改为全局,无论它在哪里使用,但同样的问题。问题是按下 ctrl + c 时不会使其进入try catch 块的except 部分
  • 它没有进入while grabber.isAlive():循环,我改了while grabber.is_alive()它在windows10中工作

标签: python multithreading python-multithreading


【解决方案1】:

PS(本来想在评论中添加这个,但我不能,因为我不符合要求)

我将把解释留给其他人,因为我无法让您的代码在我的计算机上运行。

但是您是否考虑过在 except 块的末尾添加一个 sys.exit(0) ?每当我尝试使用 KeyboarInterrupt 来摆脱这个小代码 sn-p 时,它都会对我产生影响:

import sys

if __name__ == "__main__":
     while True:

         try:
             print("Hello")
         except KeyboardInterrupt:
             print("Exiting...")
             sys.exit(0)

PS:如果您最终删除了 sys.exit() 部分,请使用 Ctrl+Z 并手动终止进程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    • 2019-09-05
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多