python picamera,键盘ctrl + c / sigint未被捕获

时间:2017-10-13 16:58:22

标签: python raspberry-pi sigint

pycamera docs开始,我采用了快速捕获和处理的示例,并添加了一个sigint事件处理程序来捕获键盘中断:

import io
import time
import threading
import picamera

# Create a pool of image processors
done = False
lock = threading.Lock()
pool = []

def signal_handler(signal, frame):
    global done
    print 'You pressed Ctrl+C!'
    done=True
    sys.exit()

signal.signal(signal.SIGINT, signal_handler)
class ImageProcessor(threading.Thread):
    def __init__(self):
        super(ImageProcessor, self).__init__()
        self.stream = io.BytesIO()
        self.event = threading.Event()
        self.terminated = False
        self.daemon=True;
        self.start()

    def run(self):
        # This method runs in a separate thread
        global done
        while not self.terminated:
            # Wait for an image to be written to the stream
            if self.event.wait(1):
                try:
                    self.stream.seek(0)
                    # Read the image and do some processing on it
                    #Image.open(self.stream)
                    #...
                    #...
                    # Set done to True if you want the script to terminate
                    # at some point
                    #done=True
                finally:
                    # Reset the stream and event
                    self.stream.seek(0)
                    self.stream.truncate()
                    self.event.clear()
                    # Return ourselves to the pool
                    with lock:
                        pool.append(self)

def streams():
    while not done:
        with lock:
            if pool:
                processor = pool.pop()
            else:
                processor = None
        if processor:
            yield processor.stream
            processor.event.set()
        else:
            # When the pool is starved, wait a while for it to refill
            time.sleep(0.1)

with picamera.PiCamera() as camera:
    pool = [ImageProcessor() for i in range(4)]
    camera.resolution = (640, 480)
    camera.framerate = 30
    camera.start_preview()
    time.sleep(2)
    camera.capture_sequence(streams(), use_video_port=True)

# Shut down the processors in an orderly fashion
while pool:
    with lock:
        processor = pool.pop()
    processor.terminated = True
    processor.join()

但是中断信号永远不会被捕获。

camera.capture_sequence(streams(), use_video_port=True)运行之前,信号被捕获,在capture_sequence启动后,不会调用信号处理程序。

我是python的新手,所以答案很简单。我在这里做错了什么?

修改

如果我删除以下代码,则会捕获信号:

 yield processor.stream

2 个答案:

答案 0 :(得分:1)

问题在于你正在使用thread.join(),它会阻塞主线程,这意味着你的程序必须等到你加入的线程结束才能继续。

信号将始终被主进程捕获,因为它是接收信号的信号,它是具有线程的进程。

关于如何处理主线程和CTRL + C有很多答案,我给你三个选项,

首先,为join()调用添加超时:

thread1.join(60)详情here

其次,启动一个新进程来处理信号以杀死该程序。

class Watcher():  

    def __init__(self):  
        self.child = os.fork()  
        if self.child == 0:  
            return  
        else:  
            self.watch()  

    def watch(self):  
        try:  
            os.wait()  
        except KeyboardInterrupt:  
            self.kill()  
        sys.exit()  

    def kill(self):  
        try:  
            os.kill(self.child, signal.SIGKILL)  
        except OSError:  
            pass  

在你开始工作线程之前启动一个Watcher,比如

def main():  
    init()  
    Watcher()  
    start_your_thread1()  
    start_your_thread2()  
    start_your_thread3() 

最后,你的原始方式,复杂的生产者和消费者方式。

只需删除最后的join(),并为主线程添加一些任务。

我更喜欢第二个选项,它很容易使用,并解决了Python中多线程程序的两个问题,(1)信号可能被传递到任何线程(这只是一个错误的特征)和(2)如果得到的线程信号在等待,信号被忽略(这是一个错误)。 关于观察者的更多细节见书The Little Book of Semaphores

的附录A.

答案 1 :(得分:0)

在您的代码中,done变量是一个全局变量。 因此,每当您想在函数内修改它时,您需要使用关键字global,否则它将成为局部变量。

你应该修改你的代码:

import signal
import sys

done = False


def signal_handler(signal, frame):
    global done
    print('You pressed Ctrl+C!')
    done = True
    sys.exit()


signal.signal(signal.SIGINT, signal_handler)