Python 为什么不捕获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_

我有以下捕获Ctrl+C的标准实现:

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