当前位置: 动力学知识库 > 问答 > 编程问答 >

multithreading - Is this a valid way to subclass a python thread to accept a variable update?

问题描述:

I'm looking at the threading module in Python (version 3.4.3), and am having difficulty finding a way to update a variable in the target function that is called. I think I could create a global variable to share between the main program and the thread that I am starting, but found myself creating the following subclass instead. This seems to work for my purposes, but I'm curious if this is just a hack or if it's valid.

The goal here is to create a separate thread that regularly (and quietly) pings a server, and then updates a specified widget with the status of the update:

from tkinter import *

import threading

class ipthread(threading.Thread):

def __init__(self, ip=None, labelobj=None):

self.ip = ip

threading.Thread.__init__(self, target=self.checkconnection, args=(labelobj,))

def newip(self, ip):

self.ip = ip

def checkconnection(self, widget):

while True:

self.response = os.system("ping -c 1 -W 10 " + self.ip + " > /dev/null 2> /dev/null")

if self.response==0:

widget.config(text="connected", bg='green')

else:

widget.config(text="no connection", bg='red')

time.sleep(1)

if __name__=="__main__":

win = Tk()

status = Label(win, text='')

status.pack()

ipchecker = ipthread(ip='192.168.1.1',widget=status)

time.sleep(10)

ipchecker.newip('192.168.1.2')

While I've put a simple routine here that calls the update after a 10-second delay, in my program the thread is initialized when I create a tkinter Frame control panel. The panel has a button that then calls the newip method to update the thread. It works, so I'm feeling like I've accomplished something, but is it overkill or unnecessary? I couldn't find another way to initialize the "checkconnection" routine as a separate thread, and then be able to update the ip address its using.

网友答案:

You ask several questions, I'll hopefully answer them all.

Is this a valid way to pass arguments to a thread?

There are two ways to pass arguments to a thread:

  • Subclass Thread, redefine the function run and access the new variables from there, as in

    class ipthread(threading.Thread):
      def __init__(self, ip=None, labelobj=None):
        self.ip = ip
        self.labelobj = labelobj
    
      def newip(self, ip):
        self.ip = ip
    
      def run(self):
        while True:
            self.response = os.system("ping -c 1 -W 10 " + self.ip + " > /dev/null 2> /dev/null")
            if self.response==0:
                self.labelobj.config(text="connected", bg='green')
            else:
                self.labelobj.config(text="no connection", bg='red')
            time.sleep(1)
    
  • Or you could specify the target to call

    def checkconnection(widget, ip):
        while True:
            self.response = os.system("ping -c 1 -W 10 " + self.ip + " > /dev/null 2> /dev/null")
            if self.response==0:
                widget.config(text="connected", bg='green')
            else:
                widget.config(text="no connection", bg='red')
            time.sleep(1)
    
    th = threading.Thread(target=checkconnection, args=(labelobj, ip))
    th.start()
    

Is this the proper solution for this problem?

No, it is not!

Widget libraries normally do not like a second thread to cut across their widgets. You could use a TKInter timer instead of a thread, or use a custom event to let the thread tell the widget that the text has changed.

When using a timer, the GUI becomes unresponsive while the tick is being handled. In your case, the ping has an unbounded delay so I would keep the thread and let it send a custom event.

分享给朋友:
您可能感兴趣的文章:
随机阅读: