为什么不捕获CTRL-C并调用signal_handler? [英] Why is CTRL-C not captured and signal_handler called?

查看:275
本文介绍了为什么不捕获CTRL-C并调用signal_handler?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following standard implementation of capturing Ctrl+C:

def signal_handler(signal, frame):
    status = server.stop()
    print("[{source}] Server Status: {status}".format(source=__name__.upper(),
                                                      status=status))
    print("Exiting ...")

    sys.exit(0)


signal.signal(signal.SIGINT, signal_handler)

server.start()上,我正在启动CherryPy的线程实例.我创建了一个线程,以为可能是因为CherryPy正在运行,所以主线程没有看到 Ctrl + C .这似乎没有任何影响,但是将代码发布为我现在有它:

On server.start() I am starting a threaded instance of CherryPy. I created the thread thinking that maybe since CherryPy is running, the main thread is not seeing the Ctrl+C. This did not seem to have any affect but posting the code as I have it now:

__ main __ :

   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 时,应用程序不会停止.我在上面的signal_handler中放置了一个断点,但从未命中它.

When I press Ctrl+C the application does not stop. I have placed a breakpoint in the signal_handler above and it is never hit.

推荐答案

最终要实现的目标还不太清楚,但似乎您错过了CherryPy设计的重点.

It's not quite clear what you want to achieve in the end, but it looks like you miss important point of CherryPy design.

CherryPy状态和组件编排围绕 CherryPy插件,它将坚持服务器的状态.

CherryPy state and component orchestration is built around the message bus. To you as a developer it's also an abstraction from OS-specific signalling. So if you want to have a thread, it is a good idea to wrap in into CherryPy plugin which will adhere to state of the server.

#!/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图.

More explicitly about handling SIGINT signal. Here's the FSM diagram from the first link.

                 O
                 |
                 V
STOPPING --> STOPPED --> EXITING -> X
   A   A         |
   |    \___     |
   |        \    |
   |         V   V
 STARTED <-- STARTING

您的兴趣是STOPPINGEXITING,因为两者都与处理SIGINT有关.区别在于STOPPING可能会发生多次,例如守护服务器守护进程时,SIGHUP使其重新启动.因此,您只需将终止例程放入ExamplePlugin.exit.

Your interest is either STOPPING or EXITING as both relate to handling SIGINT. The difference is that STOPPING may occur several times e.g. when the server is daemonised SIGHUP makes it restart. So you can just put your termination routine in ExamplePlugin.exit.

这篇关于为什么不捕获CTRL-C并调用signal_handler?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆