Defering to the GTK thread

A method that is often mentioned is defering the gtk call to the main thread. In general what this means is that in threads instead of calling a gtk/gdk call directly, you inbed it in a gobject.idle_add call. The working threads then become something like the following. (A full demo implementing this idea can be found in demo3a.py.)

    class Counting (Thread):
    
        def __init__(self, Id)
    
        def run(self):
            while ...:
                Calculate Results 
                gob.idle_add(canvas.Adjust, self.Id, self.ShowTime , self.ShowValue)

        def Start_Stop(self,ignore)
    
        def Modus(self,ignore):
            if Running:
                Change Mode
            else:
                Reset Values
                gob.idle_add(canvas.Adjust, self.Id, self.Time , self.Value)
		
        def Quit(self):
            Make thread leave loop

However what we have here is essentially an unbounded Queue. That may work in a lot of cases but again in our demo the working threads produce more results than the gtk thread can process, So we get very sluggisch and erratic behaviour (even had a crash) .

The next solution I propose is a tube. A tube is a Queue like object but with important differences that make it more usefull in the gtk environment.

  1. A thread has to open (read and/or write) a tube before it can access it.

  2. A thread that has read/write access to a tube can put items on a full tube. This prevents certain types of deadlock

  3. If all writers close the tube, an attempt to read from an empty tube will raise an exception in the reader

  4. A tube can be registered with tube_add, an io_add like call.

So first we need a function that will get an element from the tube and process it, This fuction will be registered later, Something like:

    def Draw():
        try:
	    Id, ShowTime, ShowValue = Tube.get()
            canvas.Adjust(Id, ShowTime , ShowValue)
	except EOInformation:
	    gtk.main_quit()

The working threads are like in the Queue example except for the opening of the Tube in the beginning and the absence of gtk lock calls.

    class Counting (Thread):
    
        def __init__(self, Id)
    
        def run(self):
	    Tube.open("r")
            while ...:
                Calculate Results 
                Tube.put((self.Id, self.ShowTime , self.ShowValue))

        def Start_Stop(self,ignore)
    
        def Modus(self,ignore):
            if Running:
                Change Mode
            else:
                Reset Values
                Tube.put((self.Id, self.ShowTime , self.ShowValue))
		
        def Quit(self):
            Make thread leave loop

The only thing left is for the gtk-thread to open the tube and register it before starting. This would do it.

    Tube.open("rw")
    tube_add_watch(Tube, Draw)
    gtk.main()

There are two implementations for the tube module iotube.py. and idletube.py. The demo demonstrating this idea is demo3b.py.)

PREV NEXT