从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
答案 0 :(得分:1)
问题在于你正在使用thread.join()
,它会阻塞主线程,这意味着你的程序必须等到你加入的线程结束才能继续。
信号将始终被主进程捕获,因为它是接收信号的信号,它是具有线程的进程。
关于如何处理主线程和CTRL + C有很多答案,我给你三个选项,
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)