编程语言
首页 > 编程语言> > python – 为什么没有捕获CTRL-C并调用signal_handler?

python – 为什么没有捕获CTRL-C并调用signal_handler?

作者:互联网

我有以下捕获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.这似乎没有任何影响,但发布代码,因为我现在拥有它:

__主要__:

   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中放置了一个断点,它永远不会被击中.

解决方法:

目前还不太清楚你想要达到的目标,但看起来你错过了CherryPy设计的重点.

CherryPy状态和组件编排是在the message bus左右构建的.作为开发人员,它也是特定于操作系统的信令的抽象.因此,如果你想拥有一个线程,最好将其包含到CherryPy plugin中,这将遵循服务器的状态.

#!/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)

UPDATE

更明确地说明了处理SIGINT信号.这是第一个链接的FSM图.

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

您的兴趣是停止或退出,因为两者都与处理SIGINT有关.不同之处在于STOPPING可能会发生几次,例如当服务器被守护时,SIGHUP使它重新启动.所以你可以把你的终止例程放在ExamplePlugin.exit中.

标签:python,cherrypy,sigint
来源: https://codeday.me/bug/20191003/1846765.html