title: Beginner-level Python threading problems
body: <p>As someone new to GUI development in Python (with pyGTK), I've just started learning about threading. To test out my skills, I've written a simple little GTK interface with a start/stop button. The goal is that when it is clicked, a thread starts that quickly increments a number in the text box, while keeping the GUI responsive.</p>
  
  <p>I've got the GUI working just fine, but am having problems with the threading. It is probably a simple problem, but my mind is about fried for the day. Below I have pasted first the trackback from the Python interpreter, followed by the code. You can go to <a href="http://drop.io/pxgr5id" rel="noreferrer">http://drop.io/pxgr5id</a> to download it. I'm using bzr for revision control, so if you want to make a modification and re-drop it, please commit the changes. I'm also pasting the code at <a href="http://dpaste.com/113388/" rel="noreferrer">http://dpaste.com/113388/</a> because it can have line numbers, and this markdown stuff is giving me a headache.</p>
  
  <p>Update 27 January, 15:52 EST:
  Slightly updated code can be found here: <a href="http://drop.io/threagui/asset/thread-gui-rev3-tar-gz" rel="noreferrer">http://drop.io/threagui/asset/thread-gui-rev3-tar-gz</a></p>
  
  <p><strong>Traceback</strong></p>
  
  <pre><code>crashsystems@crashsystems-laptop:~/Desktop/thread-gui$ python threadgui.pybtnStartStop clicked
  Traceback (most recent call last):
    File "threadgui.py", line 39, in on_btnStartStop_clicked
      self.thread.stop()
    File "threadgui.py", line 20, in stop
      self.join()
    File "/usr/lib/python2.5/threading.py", line 583, in join
      raise RuntimeError("cannot join thread before it is started")
  RuntimeError: cannot join thread before it is started
  btnStartStop clicked
  threadStop = 1
  btnStartStop clicked
  threadStop = 0
  btnStartStop clicked
  Traceback (most recent call last):
    File "threadgui.py", line 36, in on_btnStartStop_clicked
      self.thread.start()
    File "/usr/lib/python2.5/threading.py", line 434, in start
      raise RuntimeError("thread already started")
  RuntimeError: thread already started
  btnExit clicked
  exit() called
  </code></pre>
  
  <p><strong>Code</strong></p>
  
  <pre><code>#!/usr/bin/bash
  import gtk, threading
  
  class ThreadLooper (threading.Thread):
      def __init__ (self, sleep_interval, function, args=[], kwargs={}):
          threading.Thread.__init__(self)
          self.sleep_interval = sleep_interval
          self.function = function
          self.args = args
          self.kwargs = kwargs
          self.finished = threading.Event()
  
      def stop (self):
          self.finished.set()
          self.join()
  
      def run (self):
          while not self.finished.isSet():
              self.finished.wait(self.sleep_interval)
              self.function(*self.args, **self.kwargs)
  
  class ThreadGUI:
      # Define signals
      def on_btnStartStop_clicked(self, widget, data=None):
          print "btnStartStop clicked"
          if(self.threadStop == 0):
              self.threadStop = 1
              self.thread.start()
          else:
              self.threadStop = 0
              self.thread.stop()
          print "threadStop = " + str(self.threadStop)
  
      def on_btnMessageBox_clicked(self, widget, data=None):
          print "btnMessageBox clicked"
          self.lblMessage.set_text("This is a message!")
          self.msgBox.show()
  
      def on_btnExit_clicked(self, widget, data=None):
          print "btnExit clicked"
          self.exit()
  
      def on_btnOk_clicked(self, widget, data=None):
          print "btnOk clicked"
          self.msgBox.hide()
  
      def on_mainWindow_destroy(self, widget, data=None):
          print "mainWindow destroyed!"
          self.exit()
  
      def exit(self):
          print "exit() called"
          self.threadStop = 1
          gtk.main_quit()
  
      def threadLoop(self):
          # This will run in a thread
          self.txtThreadView.set_text(str(self.threadCount))
          print "hello world"
          self.threadCount += 1
  
      def __init__(self):
          # Connect to the xml GUI file
          builder = gtk.Builder()
          builder.add_from_file("threadgui.xml")
  
          # Connect to GUI widgets
          self.mainWindow = builder.get_object("mainWindow")
  
          self.txtThreadView = builder.get_object("txtThreadView")
          self.btnStartStop = builder.get_object("btnStartStop")
          self.msgBox = builder.get_object("msgBox")
          self.btnMessageBox = builder.get_object("btnMessageBox")
          self.btnExit = builder.get_object("btnExit")
          self.lblMessage  = builder.get_object("lblMessage")
          self.btnOk = builder.get_object("btnOk")
  
          # Connect the signals
          builder.connect_signals(self)
  
          # This global will be used for signaling the thread to stop.
          self.threadStop = 1
  
          # The thread
          self.thread = ThreadLooper(0.1, self.threadLoop, (1,0,-1))
          self.threadCounter = 0
  
  if __name__ == "__main__":
      # Start GUI instance
      GUI = ThreadGUI()
      GUI.mainWindow.show()
      gtk.main()
  </code></pre>