Python 为什么不捕获CTRL-C并调用信号处理程序?
我有以下捕获Ctrl+C的标准实现: 在Python 为什么不捕获CTRL-C并调用信号处理程序?,python,cherrypy,sigint,Python,Cherrypy,Sigint,我有以下捕获Ctrl+C的标准实现: 在server.start()上,我正在启动CherryPy的一个线程实例。我创建线程的想法是,可能因为CherryPy正在运行,主线程没有看到Ctrl+C。这似乎没有任何影响,但发布了我现在拥有的代码: \uuuuuu main\uuuuuuu: server.start() 服务器: def start(self): # self.engine references cherrypy.engine self.__cherry_
server.start()
上,我正在启动CherryPy的一个线程实例。我创建线程的想法是,可能因为CherryPy正在运行,主线程没有看到Ctrl+C。这似乎没有任何影响,但发布了我现在拥有的代码:
\uuuuuu main\uuuuuuu:
server.start()
服务器:
def start(self):
# self.engine references cherrypy.engine
self.__cherry_thread = threading.Thread(target=self.engine.start)
self.status['running'] = True
self.status['start_time'] = get_timestamp()
self.__cherry_thread.start()
def stop(self):
self.status['running'] = False
self.status['stop_time'] = get_timestamp()
self.engine.exit()
self.__thread_event.set()
return self.status
当我按下Ctrl+C时,应用程序不会停止。我在上面的
信号处理程序中放置了一个断点,但它从未被命中。不太清楚您最终想要实现什么,但看起来您错过了CherryPy设计的要点
CherryPy状态和组件编排是围绕此构建的。对于开发人员来说,这也是对操作系统特定信令的抽象。所以,若您想拥有一个线程,最好将其封装到一个将遵循服务器状态的线程中
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import threading
import time
import logging
import cherrypy
from cherrypy.process.plugins import SimplePlugin
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
}
}
class ExamplePlugin(SimplePlugin):
_thread = None
_running = None
_sleep = None
def __init__(self, bus, sleep = 2):
SimplePlugin.__init__(self, bus)
self._sleep = sleep
def start(self):
'''Called when the engine starts'''
self.bus.log('Setting up example plugin')
# You can listen for a message published in request handler or
# elsewhere. Usually it's putting some into the queue and waiting
# for queue entry in the thread.
self.bus.subscribe('do-something', self._do)
self._running = True
if not self._thread:
self._thread = threading.Thread(target = self._target)
self._thread.start()
# Make sure plugin priority matches your design e.g. when starting a
# thread and using Daemonizer which forks and has priority of 65, you
# need to start after the fork as default priority is 50
# see https://groups.google.com/forum/#!topic/cherrypy-users/1fmDXaeCrsA
start.priority = 70
def stop(self):
'''Called when the engine stops'''
self.bus.log('Freeing up example plugin')
self.bus.unsubscribe('do-something', self._do)
self._running = False
if self._thread:
self._thread.join()
self._thread = None
def exit(self):
'''Called when the engine exits'''
self.unsubscribe()
def _target(self):
while self._running:
try:
self.bus.log('some periodic routine')
time.sleep(self._sleep)
except:
self.bus.log('Error in example plugin', level = logging.ERROR, traceback = True)
def _do(self, arg):
self.bus.log('handling the message: {0}'.format(arg))
class App:
@cherrypy.expose
def index(self):
cherrypy.engine.publish('do-something', 'foo')
return 'Look in the terminal or log'
if __name__ == '__main__':
ExamplePlugin(cherrypy.engine).subscribe()
cherrypy.quickstart(App(), '/', config)
更新
更明确地处理SIGINT信号。这是第一个链接的FSM图
O
|
V
STOPPING --> STOPPED --> EXITING -> X
A A |
| \___ |
| \ |
| V V
STARTED <-- STARTING
O
|
v
停止-->停止-->退出->X
A|
| \___ |
| \ |
|V V
从何处开始运行代码以设置信号处理程序?信号处理程序设置与服务器位于同一源文件(位于顶部)中。所以当main导入服务器时,所有的设置都应该完成,对吗?信号不会传播到子线程。@roippi:即使我删除\uu cherry\u线程
并直接调用engine.start()
,也不会捕获Ctrl+C
。我知道CherryPy可能在子线程上运行,但是如何让主线程识别SIGINT
?好的,这是关于如何使用自定义配置正确实现CherryPy的重要信息。但这不是我的问题(尽管这个答案在我实现的其余部分确实给了我有用的信息)。使用此自定义配置,我在哪里实现捕获SIGINT并关闭?@IAbstract我不认为每个问题都必须逐字回答,因为通常有更好的建议路径。例如,在这里,我的答案是告诉您和未来的读者,您通常不需要自己处理操作系统信号。CherryPy无论如何都会这样做,所以您可以只关注服务器的状态。子类化SimplePlugin
很容易,因为它会自动订阅开始
,停止
,退出
,优雅
。我还添加了通用插件的模式和警告,使其更加有用和清晰。我已经用SIGINT相关的状态和建议更新了我的答案,看一看。我们可以同意在答案是否需要文字上存在分歧。我对Python还是相当陌生的,刚刚开始自己深入研究CherryPy。我还没有完全理解架构以及如何扩展CherryPy。也就是说,我仍然不确定如何/在何处放置此示例中的sigint_处理程序。:/你是说CherryPy已经有了一个sigint_处理程序吗?@IAbstract 1)对于初学者来说,提供你最终想要实现的目标的细节也是一个好主意,比如线程的用途2)Python本机处理Ctrl+C,并引发()3)当然CherryPy处理键盘中断(sigint)和SIGTERM,SIGHUP和SIGUSR1。所以我重复一遍,将终止代码放入ExamplePlugin.exit
,让CherryPy为您处理信号。
O
|
V
STOPPING --> STOPPED --> EXITING -> X
A A |
| \___ |
| \ |
| V V
STARTED <-- STARTING