当我退出应用程序(代码如下)时,我使用 subprocess.Popen
启动的两个 ping 进程不会自动终止,并且仍然显示在 Windows 7 任务列表中。
当应用程序运行时,ping 进程在 Python.exe 下显示为两个线程。当应用程序退出时,这两个进程将移动到系统进程选项卡并继续在那里运行。
我该如何解决这个问题?我希望在我的应用程序关闭时终止这两个 ping 进程。
# -*- coding: utf-8 -*-
import sys
import time
import subprocess
from threading import Thread
import re
from PyQt4.QtGui import QMainWindow, QApplication, QStandardItemModel, QStandardItem, QWidget, QVBoxLayout, QTableView
from PyQt4.QtCore import pyqtSignature, Qt, QTimer, SIGNAL, QString, QMetaObject
from Queue import Queue
try:
_fromUtf8 = QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(500, 435)
self.centralWidget = QWidget(MainWindow)
self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
self.verticalLayout = QVBoxLayout(self.centralWidget)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
self.tableView = QTableView(self.centralWidget)
self.tableView.setObjectName(_fromUtf8("tableView"))
self.verticalLayout.addWidget(self.tableView)
MainWindow.setCentralWidget(self.centralWidget)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QApplication.translate("MainWindow", "Ping Tester", None, QApplication.UnicodeUTF8))
if sys.platform.startswith('linux'):
getdata = re.compile(r"icmp_req=(\d+) ttl=(\d+) time=([\d\.]+)\sms")
pingstr = ["ping", "-n", "-i 0.2"]
filtered = "Packet filtered"
delaytime = 200
else:
getdata = re.compile(r"=([\d\.]+)ms TTL=(\d+)")
pingstr = ["ping.exe", "-t"]
timeout = "Request timed out."
delaytime = 500
try:
with open("ips.conf", "r") as f:
t_node = f.read().decode('utf-8')
if not t_node:
raise IOError
except IOError:
with open("ips.conf", "w") as f:
t_node = u"""
8.8.8.8-Google
184.22.112.34-USAHE
"""
f.write(t_node.encode('utf-8'))
node = []
for line in t_node.split('\n'):
try:
ip, desc = line.strip().split("-")
node.append((ip, desc))
except ValueError:
pass
nodecount = len(node)
class MainWindow(QMainWindow, Ui_MainWindow):
"""
Class documentation goes here.
"""
def __init__(self, parent = None):
"""
Constructor
"""
QMainWindow.__init__(self, parent)
self.setupUi(self)
self.model = QStandardItemModel()
self.model.setColumnCount(6)
self.model.setRowCount(nodecount)
self.model.setHorizontalHeaderLabels(["IP", "Description", "Loss%", "CurPing", "AvgPing", "TTL"])
for i, (ip, desc) in enumerate(node):
self.setitem(i, 0, ip)
self.setitem(i, 1, desc)
self.setitem(i, 2, "")
self.setitem(i, 3, "")
self.setitem(i, 4, "")
self.setitem(i, 5, "")
self.tableView.setModel(self.model)
for i in range(len(node)):
self.tableView.setRowHeight(i, 18)
self.resizetable()
self.timer = QTimer(self)
self.connect(self.timer,
SIGNAL("timeout()"),
self.checkitems)
self.timer.start(delaytime)
def checkitems(self):
while not q.empty():
item = q.get()
self.chgtxt(*item)
q.task_done()
self.resizetable()
def resizetable(self):
self.tableView.resizeColumnsToContents()
def chgtxt(self, x, y, value):
self.model.item(x, y).setText(value)
def setitem(self, x, y, value):
self.model.setItem(x, y, QStandardItem(value))
app = QApplication(sys.argv)
ui = MainWindow()
ui.show()
q = Queue()
def pinger(i, ip, desc):
s = ""
avgping = 0
count = 0
timeoutcount = 0
ret = subprocess.Popen(pingstr + [ip],
stdout=subprocess.PIPE)
while True:
try:
s += ret.stdout.read(1)
tryfind = getdata.findall(s)
if sys.platform.startswith('linux'):
if len(tryfind) > 0:
req, ttl, crtping = tryfind[-1]
avgping += float(crtping)
count += 1
q.put((i, 3, crtping + "ms"))
q.put((i, 4, "%.2f" % (avgping * 1.0 / count) + "ms"))
q.put((i, 5, ttl))
q.put((i, 2, "%.2f" % ((int(req) - count) * 100.0 / int(req))))
s = ""
elif filtered in s:
q.put((i, 2, "Failed"))
q.put((i, 3, "Failed"))
q.put((i, 4, "Failed"))
q.put((i, 5, "Failed"))
ret.kill()
s = ""
else:
if len(tryfind) > 0:
crtping, ttl = tryfind[-1]
avgping += float(crtping)
count += 1
q.put((i, 3, crtping + "ms"))
q.put((i, 4, "%.2f" % (avgping * 1.0 / count) + "ms"))
q.put((i, 5, ttl))
q.put((i, 2, "%.2f" % (timeoutcount * 100.0 / (count + timeoutcount))))
elif timeout in s:
timeoutcount += 1
q.put((i, 2, "-"))
q.put((i, 3, "-"))
if count:
q.put((i, 5, "%.2f" % (timeoutcount * 100.0 / (count + timeoutcount))))
else:
q.put((i, 5, "-"))
s = ""
except IOError:
print s
break
def startworkers():
for i, (ip, desc) in enumerate(node):
worker = Thread(target=pinger, args=(i, ip, desc))
worker.setDaemon(True)
worker.start()
time.sleep(delaytime / 10000.0)
startthread = Thread(target=startworkers)
startthread.setDaemon(True)
startthread.start()
sys.exit(app.exec_())
最佳答案
这是一种使用 atexit
的方法:
import subprocess
from threading import Thread
import sys
import atexit
from PyQt4.QtGui import QMainWindow, QApplication
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(("MainWindow"))
MainWindow.resize(500, 435)
def runproc():
p = subprocess.Popen(["sleep", "500"])
atexit.register(kill_proc, p)
p.communicate()
def kill_proc(proc):
try:
proc.terminate()
except Exception:
pass
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.resize(300, 300)
if __name__ == "__main__":
app = QApplication(sys.argv)
ui = MainWindow()
ui.show()
for i in range(0, 3):
t = Thread(target=runproc)
t.start()
sys.exit(app.exec_())
每个线程都会注册一个 atexit
回调,该回调传递它创建的 Popen
对象。当进程通过正常方式退出时,atexit 处理程序将被调用,并且在每个处理程序中,我们都会对 Popen
对象调用 terminate
,从而终止该进程。请注意,这不会处理有人向您的进程发送 SIGKILL 之类的信号;它仅通过关闭 QMainWindow 来退出,或者通过 CLI 运行时执行 Ctrl+C 之类的操作。
编辑:
要处理关闭时出现的异常,您必须更改代码处理从子进程的 stdout
读取的数据的方式。当您在关闭时终止子进程时,它们会将 None
发送到其 stdout
,并且您的线程会尝试处理该 None
,就好像它是实际数据一样。您只需要优雅地处理这种情况即可:
out = ret.stdout.read(1)
if not out:
break
s += out
print s
tryfind = getdata.findall(s)
关于python - 当应用程序退出时,使用 Python subprocess 模块启动的进程不会被终止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24410518/