There have been a number of posts about calling gui methods from other
threads. Eric Brunel. has reccommended calling the gui's
..event_generat e method with data passed thru a queue. This worked
great for me until trying to write to the gui from multiple threads.
There I had problems: random typesof crashes almost all resulting in
seg faults. I thought this info might help anyone trying to do the
sameor at least save some time debugging.
I wrote a (hopefully) simple and minimal piece of code to demonstrate
the problem included below. My knowledge of the Tcl/Tk interface is
minimal.
Another interesting thing is it fails on some systems and not on
others. All Linux:
Runs fine on:
Dual Opteron Fedora5
Linux xxxx 2.6.16-1.2096_FC5 #1 SMP Wed Apr 19 05:14:26 EDT 2006
x86_64 x86_64 x86_64 GNU/Linux
Singe Pentium Fedora4
uname info unavailable right now
Fails on:
Singe Xeon SuSE 10.1
Linux xxxx 2.6.16.13-4-smp #1 SMP Wed May 3 04:53:23 UTC 2006 i686
i686 i386 GNU/Linux
Single Celeron 400 (Embedded BlueCat)
Linux 2.6.7 #45 i686 i686 i386 (not copy pasted)
Single Celeron 400
SuSE 10.1 - not available
My solution (others have done the same) was to go back to having the
gui thread call its own event_generate method with the event string
passed in through queue and using a polling loop with after methods.
Would someone please verify that this shouldn't be done for some reason
such as thread-safety or point out what I'm doing wrong? It seems from
some of the errors that the event data is getting overwritten. I've
included the code, if anyone wants to see some of the errors I have
saved them.
---------------------------
from Tkinter import *
import threading
import Queue
from time import sleep
import random
class Thread_0(thread ing.Thread):
def __init__(self):
threading.Threa d.__init__(self )
def run(self):
count=0
while True:
count+=1
hmi.thread_0_up date(count)
sleep(random.ra ndom()/100)
class Thread_1(thread ing.Thread):
def __init__(self):
threading.Threa d.__init__(self )
def run(self):
count=0
while True:
count+=1
hmi.thread_1_up date(count)
sleep(random.ra ndom()/100)
class HMI:
def __init__(self):
self.master=Tk( )
self.master.geo metry('200x200+ 1+1')
f=Frame(self.ma ster)
f.pack()
self.l0=Label(f )
self.l0.pack()
self.l1=Label(f )
self.l1.pack()
self.q0=Queue.Q ueue()
self.q1=Queue.Q ueue()
self.master.bin d("<<Thread_0_L abel_Update>>", self.thread_0_u pdate_e)
self.master.bin d("<<Thread_1_L abel_Update>>", self.thread_1_u pdate_e)
def start(self):
self.master.mai nloop()
self.master.des troy()
############### ############### ###
def thread_0_update (self,val):
self.q0.put(val )
self.master.eve nt_generate('<< Thread_0_Label_ Update>>',when= 'tail')
def thread_1_update (self,val):
self.q1.put(val )
self.master.eve nt_generate('<< Thread_1_Label_ Update>>',when= 'tail')
def thread_0_update _e(self,e):
while self.q0.qsize() :
try:
val=self.q0.get ()
self.l0.config( text=str(val))
except Queue.Empty:
pass
def thread_1_update _e(self,e):
while self.q1.qsize() :
try:
val=self.q1.get ()
self.l1.config( text=str(val))
except Queue.Empty:
pass
############### ###########
if __name__=='__ma in__':
hmi=HMI()
t0=Thread_0()
t1=Thread_1()
t0.start()
t1.start()
hmi.start()
---------------------------
threads. Eric Brunel. has reccommended calling the gui's
..event_generat e method with data passed thru a queue. This worked
great for me until trying to write to the gui from multiple threads.
There I had problems: random typesof crashes almost all resulting in
seg faults. I thought this info might help anyone trying to do the
sameor at least save some time debugging.
I wrote a (hopefully) simple and minimal piece of code to demonstrate
the problem included below. My knowledge of the Tcl/Tk interface is
minimal.
Another interesting thing is it fails on some systems and not on
others. All Linux:
Runs fine on:
Dual Opteron Fedora5
Linux xxxx 2.6.16-1.2096_FC5 #1 SMP Wed Apr 19 05:14:26 EDT 2006
x86_64 x86_64 x86_64 GNU/Linux
Singe Pentium Fedora4
uname info unavailable right now
Fails on:
Singe Xeon SuSE 10.1
Linux xxxx 2.6.16.13-4-smp #1 SMP Wed May 3 04:53:23 UTC 2006 i686
i686 i386 GNU/Linux
Single Celeron 400 (Embedded BlueCat)
Linux 2.6.7 #45 i686 i686 i386 (not copy pasted)
Single Celeron 400
SuSE 10.1 - not available
My solution (others have done the same) was to go back to having the
gui thread call its own event_generate method with the event string
passed in through queue and using a polling loop with after methods.
Would someone please verify that this shouldn't be done for some reason
such as thread-safety or point out what I'm doing wrong? It seems from
some of the errors that the event data is getting overwritten. I've
included the code, if anyone wants to see some of the errors I have
saved them.
---------------------------
from Tkinter import *
import threading
import Queue
from time import sleep
import random
class Thread_0(thread ing.Thread):
def __init__(self):
threading.Threa d.__init__(self )
def run(self):
count=0
while True:
count+=1
hmi.thread_0_up date(count)
sleep(random.ra ndom()/100)
class Thread_1(thread ing.Thread):
def __init__(self):
threading.Threa d.__init__(self )
def run(self):
count=0
while True:
count+=1
hmi.thread_1_up date(count)
sleep(random.ra ndom()/100)
class HMI:
def __init__(self):
self.master=Tk( )
self.master.geo metry('200x200+ 1+1')
f=Frame(self.ma ster)
f.pack()
self.l0=Label(f )
self.l0.pack()
self.l1=Label(f )
self.l1.pack()
self.q0=Queue.Q ueue()
self.q1=Queue.Q ueue()
self.master.bin d("<<Thread_0_L abel_Update>>", self.thread_0_u pdate_e)
self.master.bin d("<<Thread_1_L abel_Update>>", self.thread_1_u pdate_e)
def start(self):
self.master.mai nloop()
self.master.des troy()
############### ############### ###
def thread_0_update (self,val):
self.q0.put(val )
self.master.eve nt_generate('<< Thread_0_Label_ Update>>',when= 'tail')
def thread_1_update (self,val):
self.q1.put(val )
self.master.eve nt_generate('<< Thread_1_Label_ Update>>',when= 'tail')
def thread_0_update _e(self,e):
while self.q0.qsize() :
try:
val=self.q0.get ()
self.l0.config( text=str(val))
except Queue.Empty:
pass
def thread_1_update _e(self,e):
while self.q1.qsize() :
try:
val=self.q1.get ()
self.l1.config( text=str(val))
except Queue.Empty:
pass
############### ###########
if __name__=='__ma in__':
hmi=HMI()
t0=Thread_0()
t1=Thread_1()
t0.start()
t1.start()
hmi.start()
---------------------------