On Wed, Jun 23, 2004 at 11:05:03AM +0000, Tiago Cogumbreiro wrote:
> I for one would like to see them :) A threading tutorial is always nice.
> Making demos out of the most common concurrent patterns would also be
> interesting.
All rigt here below is my first version of a multi-threaded pygtk
program. In this version I use gtk.threads_enter()/gtk.threads_leave
pairs when I want to draw something to the screen from within
a subthread.
Personnaly I would recommed against this method except if
your subthreads are very intensive in updating the screen,
the logic of your subthread is not to complcated and you
really need the speed.
The reason is the pygtk really can get in your way with
how it handles things. Look for instance to the Counting
class. There are two methods that will adjust the screen,
run and Modus. Now in run we use the threads_enter/threads_leave
pair but we don't in Modus. Why? Well because although Modus
belongs to the Thread object it really gets called by the
main thread through a signal handler and callback that are
connected are implicitly squeezed between a threads_enter/threads_leave
pair when called.
That is also the reason why the On_Delete method of Frame starts
with a threads_leave() call. Your sunthreads are likely to be
blocked by the threads_enter() call in run. So just Quitting
and joining the subthreads in On_Delete will very likely cause
a deadlock if you didn't call threads_leave() first.
So lots of things to look out for if you try it this way.
--------------------- demo1.py ----------------------------------
import gtk
import gtk.gdk as gdk
import pango
from threading import Thread, Lock
from random import Random, randint, shuffle
from time import sleep
rndfl=file('/dev/random')
class Counting (Thread):
def __init__(self, Id):
self.Id = Id
self.ctrl = True
self.Running = False
self.ShowMode = 0
self.Time = 0
self.Value = 250
self.lock = Lock()
self.lock.acquire()
self.PRG = Random()
self.PRG.seed(rndfl.read(8))
Thread.__init__(self)
# __init__
def run(self):
def limit(x, sub, sup):
if x < sub:
return sub
elif x > sup:
return sup
else:
return x
# if
# limit
if not self.Running:
self.lock.acquire()
# if
while self.ctrl:
OldTime = self.Time
self.Time = OldTime + self.PRG.randint(1,20)
while OldTime < self.Time:
OldTime += 1
# while
#sleep(self.PRG.uniform(0.01, 0.03))
self.Value = limit(self.Value + self.PRG.randint(-5,5) , 0 , 500)
if self.ShowMode != 3:
if self.ShowMode % 2 == 0:
self.ShowValue = self.Value
# if
if self.ShowMode / 2 == 0:
self.ShowTime = self.Time
# if
gtk.threads_enter()
canvas.Adjust (self.Id, self.ShowTime , self.ShowValue)
gdk.flush()
gtk.threads_leave()
# if
if not self.Running:
self.lock.acquire()
# if
# while
# run
def Start_Stop(self,ignore):
if self.Running:
self.Running = False
else:
self.Running = True
self.lock.release()
# if
# Start_Stop
def Modus(self,ignore):
if self.Running:
self.ShowMode = (self.ShowMode + 1) % 4
else:
if self.ShowMode == 0:
self.Time = 0
self.Value = 250
else:
self.ShowMode = 0
# if
canvas.Adjust(self.Id, self.Time, self.Value)
# if
# Modus
def Quit(self):
self.ctrl = False
if not self.Running:
self.Running = True
self.lock.release()
# if
# Quit
# Counting
Worker = [ Counting(i) for i in xrange(7) ]
S = range(7)
shuffle(S)
for i in S:
Worker[i].start()
# for
Rnd = Random()
Rnd.seed()
RowHght = 25
BtnSize = (75, RowHght)
#ColorScale = 65535
ColorScale = 3 * 65535 / 5
class Canvas(gtk.DrawingArea):
def __init__(self):
def On_Expose(canvas, evt):
gc = canvas.window.new_gc()
lb = canvas.window.new_gc()
cm = gc.get_colormap()
for i in xrange(7):
r = (i & 4) >> 2
g = (i & 2) >> 1
b = (i & 1) >> 0
color = cm.alloc_color(r * ColorScale, g * ColorScale, b * ColorScale )
gc.set_foreground(color)
canvas.window.draw_rectangle(gc, True , 75, (2 * i + 1) * RowHght ,
canvas.ThrdInfo[i][1] , RowHght )
canvas.layout.set_text("%8d" % (canvas.ThrdInfo[i][0],))
canvas.window.draw_layout(lb, 5 , (2 * i + 1) * RowHght + canvas.TxtPad ,
canvas.layout)
# for
# On_Expose
def On_Update(canvas, Results):
pass
# On_Update
gtk.DrawingArea.__init__(self)
self.add_events(gdk.BUTTON_PRESS_MASK)
self.set_size_request(600, 15 * RowHght)
self.layout = self.create_pango_layout("")
desc = self.layout.get_context().get_font_description()
desc.set_family("Monospace")
self.TxtPad = desc.get_size() / (2 * pango.SCALE)
self.ThrdInfo = [ [0 , 250 ][:] for x in range(7) ]
self.layout.set_font_description(desc)
self.connect("expose_event" , On_Expose)
#self.connect("update" , On_Update)
self.connect("button_press_event" , self.On_Click)
# __init__
def On_Click(self, evnt, info):
for W in Worker:
W.Start_Stop(None)
# for
# On_Click
def Adjust(self, ThrdIx, Time, Value):
r = (ThrdIx & 4) >> 2
g = (ThrdIx & 2) >> 1
b = (ThrdIx & 1) >> 0
gc = self.window.new_gc()
lb = self.window.new_gc()
cm = gc.get_colormap()
OldValue = self.ThrdInfo[ThrdIx][1]
if OldValue < Value:
color = cm.alloc_color(r * ColorScale, g * ColorScale, b * ColorScale )
gc.set_foreground(color)
self.window.draw_rectangle(gc, True , 75 + OldValue , (2 * ThrdIx + 1) * RowHght
, Value - OldValue , RowHght)
else:
color = self.style.bg[0]
gc.set_foreground(color)
self.window.draw_rectangle(gc, True , 75 + Value , (2 * ThrdIx + 1) * RowHght ,
OldValue - Value , RowHght)
# if
self.layout.set_text("%8d" % (Time,))
color = self.style.bg[0]
gc.set_foreground(color)
self.window.draw_rectangle(gc, True, 0, (2 * ThrdIx + 1) * RowHght, 75 , RowHght)
self.window.draw_layout(lb, 5 , (2 * ThrdIx + 1) * RowHght + self.TxtPad ,
self.layout)
self.ThrdInfo[ThrdIx] = [Time, Value]
# Adjust
# Canvas
class Frame(gtk.Window):
def __init__(self,canvas):
gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
self.set_title("Thread 1 Demonstration")
self.connect("delete_event" , self.On_Delete)
table = gtk.Table(15, 10, gtk.TRUE)
self.add(table)
for i in xrange(7):
Btn = gtk.Button("Start/Stop")
apply(Btn.set_size_request, BtnSize)
Btn.connect("clicked" , Worker[i].Start_Stop)
table.attach(Btn, 0, 1, 2 * i + 1, 2 * (i + 1) , 0 , 0)
Btn.show()
Btn = gtk.Button("Modus")
apply(Btn.set_size_request, BtnSize)
Btn.connect("clicked" , Worker[i].Modus)
table.attach(Btn, 1, 2, 2 * i + 1, 2 * (i + 1) , 0 , 0)
Btn.show()
# for
table.attach(canvas, 2, 10, 0, 15)
canvas.show()
table.show()
self.show()
# __init__
def On_Delete(self, widget, evt, data=None):
gtk.threads_leave()
for W in Worker:
W.Quit()
W.join()
# for
gtk.threads_enter()
gtk.main_quit()
return gtk.FALSE
gtk.threads_init()
canvas=Canvas()
Win=Frame(canvas)
gtk.main()
_______________________________________________
pygtk mailing list [EMAIL PROTECTED]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/