Threading module question

Andrew Gregory andrew.gregory at npl.co.uk
Tue Jul 13 10:40:14 EDT 2004


I've written a Tkinter application (Windows) that uses the threading
module, which I've reduced to the test case below (apologies if it's a
bit long). Using the Queue module to pass messages the callable
function in ClassDoRun can be started and interrupted via 'Start' and
'Abort' buttons. Having started then interrupted the function I
expected to be able to execute the function again from the beginning
using the 'Start' button - but I get an error message saying that the
thread is already running, even though the function has been exited.
How do I fix this?

Andrew.

# threaddemo.py
#
# Python 2.3.4 (requires Tix)
#
import threading, Queue, Tix, time

# In the full program the function below
# controls various instruments and collects data.
# A much-shortened version is given here.
class ClassDoRun:

    def __init__(self, CS):
        self.CS = CS
        
    def __call__(self):
        CS = self.CS
        for i in range(10):
            CS.Counter.set(i) # write a value for display in GUI
            time.sleep(1.0)
            if CS.AbortRun: break

class CommonStuff:   # to provide two-way common access to variables
                     # and functions by GUI and 'run' threads
    def __init__(self, root):
        self.root=root
        self.root.title("threaddemo.py, vs 12-Jul-2004")
        self.frame = Tix.Frame(root)
        self.frame.bind("<Destroy>",self.CleanUp)
        self.AbortRun=0
        self.Counter=Tix.IntVar()

    def myquit(self):
        self.root.destroy()

    def CleanUp(self, event):
        print "Cleaning up after Tkinter closed"

def ButtonBoxWidget(Fquit, Frun, Fabort, frame):
    butbox = Tix.ButtonBox(frame, orientation=Tix.HORIZONTAL)
    butbox.add('start', text='Start', underline=0, width=6,
            command=Frun)
    butbox.add('abort', text='Abort', underline=0, width=6,
            command=Fabort)
    butbox.add('quit', text='Quit', underline=0, width=6,
            command=Fquit)
    return butbox

class MainWidget(CommonStuff, Tix.TixWidget):
    def __init__(self, CS, Qput):
        self.CS = CS
        self.Qput = Qput
        self.Lcounter = Tix.Label(CS.frame, textvariable=CS.Counter)
        self.Lcounter.grid(row=0, column=0, pady=5)
        self.butbox = ButtonBoxWidget(CS.myquit, self.SendRunMessage,
self.SendAbortMessage, CS.frame)
        self.butbox.grid(row=1, column=0)
        
    def SendRunMessage(self):
        self.Qput('run')

    def SendAbortMessage(self):
        self.Qput('abort')


class Application:
    def __init__(self, CS):
        self.CS = CS
        self.Q = Queue.Queue()  # Pass messages to separate run 
                                # thread via the queue Q
        self.displayedwidget=MainWidget(CS, self.Q.put)
        CS.frame.pack()
        self.RunnableObject = ClassDoRun(CS)
        self.thread = threading.Thread(target=self.RunnableObject)
        self.poll()
        
    def MessageQueue(self): # messages e.g. Run, Abort
        self.CS.root.update()
        while self.Q.qsize():
            try:
                msg = self.Q.get(0)
                if msg=="abort": self.CS.AbortRun = 1
                if msg=="run":
                    self.CS.AbortRun=0
                    if not self.thread.isAlive(): self.thread.start()
            except Queue.Empty: pass

    def poll(self):
        #print self.thread.isAlive()
        self.MessageQueue()
        self.CS.root.after(100, self.poll)


if __name__ == '__main__':
    root = Tix.Tk()
    CS = CommonStuff(root)
    mainWin = Application(CS)
    root.mainloop()



More information about the Python-list mailing list