用Python杀死所有线程

时间:2014-03-30 00:23:39

标签: python

我有一个python脚本,它会不断ping一些IP并将结果打印到屏幕上。 但我想通过按键终止脚本(理想情况下使用q键或通过ctrl c),然后终止所有线程。

实现这一目标的最佳方法是什么?我的代码如下......

import os
import re
import time
import sys
import subprocess
import Queue
import threading

def screen_output(x, y, text):
     sys.stdout.write("\x1b7\x1b[%d;%df%s\x1b8" % (x, y, text))
     sys.stdout.flush()

class pingo:

    def __init__(self,hosts):
        self.q = Queue.Queue()
        self.all_results = {}
        self.hosts = hosts

    def send_ping(self,q,ip):
        self.q.put(self.record_results(ip))

    def record_results(self,ip):
        ping_count = 0

        host_results = {
            "device" : None,
            "sent_count" : 0,
            "success_count": 0,
            "fail_count": 0,
            "failed_perc": 0,
            "curr_status": None
            }


        while True:
            rc = subprocess.call(['ping', '-c', '1', '-W', '1', ip], stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w'))
            ping_count += 1

            # update stats

            sent_count = host_results['sent_count']
            success_count = host_results['success_count']
            fail_count = host_results['fail_count']
            failed_perc = host_results['failed_perc']
            curr_status = host_results['curr_status']

            sent_count += 1

            if rc == 0:
                success_count += 1
                curr_status = "Successful Response"
            else:
                fail_count += 1
                curr_status = "Request Timed Out"

            failed_perc =  ( fail_count / sent_count ) * 100

            host_results.update({'failed_perc': failed_perc, 'fail_count': fail_count, 'success_count': success_count, 'curr_status': curr_status, 'sent_count': sent_count})
            time.sleep(0.5)
            self.all_results.update({ip:host_results})
            screen_output(0,0,self.all_results)
        return True

    def go(self):
        for i in self.hosts:
            t = threading.Thread(target=self.send_ping, args = (self.q,i))
            #t.daemon = True
            t.start()

p =  pingo(["8.8.8.8"])
p.go()

编辑:我已尝试按建议添加全局ALIVE标志,但仍无法通过CRTL-C终止线程。

import sys
import subprocess
import Queue
import threading
import signal

def screen_output(x, y, text):
     sys.stdout.write("\x1b7\x1b[%d;%df%s\x1b8" % (x, y, text))
     sys.stdout.flush()

class pingo:

    def __init__(self,hosts):
        self.q = Queue.Queue()
        self.all_results = {}
        self.hosts = hosts
        self.ALIVE = True

    def signal_handler(self,signal, frame):
        self.ALIVE = False

    def send_ping(self,q,ip):
        self.q.put(self.record_results(ip))

    def record_results(self,ip):
        ping_count = 0

        host_results = {
            "device" : None,
            "sent_count" : 0,
            "success_count": 0,
            "fail_count": 0,
            "failed_perc": 0,
            "curr_status": None
            }


        while self.ALIVE:
            try:
                rc = subprocess.call(['ping', '-c', '1', '-W', '1', ip], stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w'))
                ping_count += 1

                # update stats

                sent_count = host_results['sent_count']
                success_count = host_results['success_count']
                fail_count = host_results['fail_count']
                failed_perc = host_results['failed_perc']
                curr_status = host_results['curr_status']

                sent_count += 1

                if rc == 0:
                    success_count += 1
                    curr_status = "Successful Response"
                else:
                    fail_count += 1
                    curr_status = "Request Timed Out"

                failed_perc =  ( fail_count / sent_count ) * 100

                host_results.update({'failed_perc': failed_perc, 'fail_count': fail_count, 'success_count': success_count, 'curr_status': curr_status, 'sent_count': sent_count})
                time.sleep(0.5)
                self.all_results.update({ip:host_results})
                screen_output(0,0,self.all_results)
            except KeyboardInterrupt:
                signal.signal(signal.SIGINT, self.signal_handler)
        return True


    def go(self):
        for i in self.hosts:
            t = threading.Thread(target=self.send_ping, args = (self.q,i))
            #t.daemon = True
            t.start()

p =  pingo(["8.8.8.8"])
p.go()

2 个答案:

答案 0 :(得分:2)

设置全局标志ALIVE(或者不一定是全局标志,可以使用dict或class属性),绑定到SIGINT并在其上更改:

import signal

ALIVE = True

def signal_handler(signal, frame):
    global ALIVE
    ALIVE = False

signal.signal(signal.SIGINT, signal_handler)

然后只需将循环更改为:

def record_results(self,ip):
    # some code
    while ALIVE:
        # some code

这样它就会优雅地退出(接收到信号后的某个时间)。

答案 1 :(得分:0)

这是Python中的顶级FAQ之一。基本上有两种方法可以做到。

  1. (优雅的方式)见@ freakish的答案。
  2. (懒惰的方式)打开所有工作线程的“守护进程”标志。例如,请参阅此问答:Understanding Python daemon threads