[pygtk] Help: Problems with threads and pygtk
Dave Aitel
dave at immunitysec.com
Sat Oct 7 05:02:31 WST 2006
Also strace it and see if a buggy linux kernel has you stuck in fmutex()...
-dave
Brian wrote:
> On Wed, 2006-04-10 at 18:58 -0700, David Hirschfield wrote:
>
>> I've run into a serious problem using threads with pygtk, and I was
>> hoping someone could give me suggestions.
>>
>> My program is a pygtk interface with a "processor" thread that pulls
>> from a safely synchronized queue of "requests" and processes each one.
>> Seems simple, and it should have been...but it freezes solid when I run
>> it. Not a traceback of any kind, the interface and the python
>> interpreter freeze.
>>
>> I've checked all the things that should be obvious problems:
>>
>> I'm calling:
>> gobject.threads_init()
>> gtk.gdk.threads_init()
>> before gtk.main() is called
>>
>> There is no race condition or blocking call causing everything to get stuck.
>> The thread's only interaction with the rest of the program is via the
>> Queue.Queue object that keeps the requests to be processed.
>>
>> I've stepped through with pdb and it freezes in a completely innocuous
>> place in the code (during a loop where I append to a list).
>> The freeze occurs in slightly different places depending on what kind of
>> debugging code I put in, changes to the order of things, etc...so it
>> feels like it's some kind of corruption in the interpreter stack.
>>
>> Running the processor thread in a dummy app without the pygtk part never
>> freezes up.
>> Running the pygtk app with a non-threaded processor, which just
>> sequentially runs the requests and waits till they complete, never
>> freezes up.
>>
>> I'm at my wit's end here...I know threads are just asking for trouble,
>> and usually I avoid them, but circumstances here basically require
>> threading (all the request time is spent waiting on different kinds of
>> IO). The setup was so simple, I figured I couldn't possibly run into
>> trouble...yet here I am.
>>
>> So, anyone have any idea what could cause the entire python interpreter
>> to freeze solid? Are there known issues with pygtk and python threads
>> that I should be aware of? Is there some way to verify that the
>> interpreter stack is not getting screwed up somehow?
>>
>> Any help at this point would really be useful,
>> -Dave
>>
>>
>
> Try this dispatcher.py module for ideas of where you may be going wrong.
> Use the dispatcher-example for how to use it for inter-thread
> communication.
>
> It has worked very well for our app and eliminated a number of problems.
>
>
>
> ------------------------------------------------------------------------
>
> #! /usr/bin/env python
> # Fredrik Arnerup <foo at stacken.kth.se>, 2004-12-19
> # Brian Dolbec<dol-sen at telus.net>,2005-3-30
>
> import gobject, os, Queue
> from select import select
>
> class Dispatcher:
> """Send signals from a thread to another thread through a pipe
> in a thread-safe manner"""
> def __init__(self, callback_func, *args, **kwargs):
> self.callback = callback_func
> self.callback_args = args
> self.callback_kwargs = kwargs
> self.continue_io_watch = True
> self.queue = Queue.Queue(0) # thread safe queue
> self.pipe_r, self.pipe_w = os.pipe()
> gobject.io_add_watch(self.pipe_r, gobject.IO_IN, self.on_data)
>
> def __call__(self, *args):
> """Emit signal from thread"""
> self.queue.put(args)
> # write to pipe afterwards
> os.write(self.pipe_w, "X")
>
> def on_data(self, source, cb_condition):
> if select([self.pipe_r],[],[], 0)[0] and os.read(self.pipe_r,1):
> if self.callback_args:
> args = self.callback_args + self.queue.get()
> self.callback(*args, **self.callback_kwargs)
> else:
> self.callback(*self.queue.get(), **self.callback_kwargs)
> return self.continue_io_watch
>
>
> ------------------------------------------------------------------------
>
> #! /usr/bin/env python
>
> # Fredrik Arnerup <foo at stacken.kth.se>, 2004-12-19
> # Brian Dolbec<dol-sen at telus.net>,2005-3-30
>
> import pygtk; pygtk.require("2.0")
> import gtk
> from time import sleep
> import threading, gobject, os
> from dispatcher import Dispatcher
>
> # ####################################
> # dispatcher
> # example code:
> #
> #
> # ####################################
>
> class Thread(threading.Thread):
>
> def __init__(self, dispatcher, thread_num, length):
> threading.Thread.__init__(self)
> self.setDaemon(1) # quit even if this thread is still running
> self.dispatcher = dispatcher
> self.thread_num = thread_num
> self.sleep_length = length
>
> def run(self):
> done = False
> print("thread_num = %s; process id = %d ****************" %(self.thread_num,os.getpid()))
> pid_func(self.thread_num)
> for num in range(250):
> #print self.thread_num, " num = ",num
> sleep(self.sleep_length)
> data = [ self.thread_num, (": time is slipping away: %d\n" %num), num, done]
> self.dispatcher(data) # signal main thread
> done = True
> data = [ self.thread_num, (": Time slipped away: I'm done"), num, done]
> self.dispatcher(data) # signal main thread
>
>
> def pid_func(threadnum):
> print("pid_func: called from thread_num = %s; process id = %d ****************" %(threadnum,os.getpid()))
>
> def message_fun(buffer, message):
> #print ("got a message : %s" %(message[0] + str(message[1])))
> if message[3]:
> thread_finished[message[0]] = True
> buffer.insert(buffer.get_end_iter(), message[0] + str(message[1]) + "\n\n")
> else:
> #message2 = ("%d x 3 = %d\n" %(message[2],message[2]*3))
> buffer.insert(buffer.get_end_iter(), message[0] + str(message[1])) # + message2)
> return
>
> def timerfunc():
> if (not thread_finished["thread1"]) or (not thread_finished["thread2"]) \
> or (not thread_finished["thread3"]) or (not thread_finished["thread4"]):
> pbar.pulse()
> #print 'Plusing ProgressBar, since a thread is not finished'
> return True
> else:
> pbar.set_fraction(0)
> pbar.set_text("Done")
> return False
>
> def on_window_map_event(event, param):
> print 'Window mapped'
> thread1 = Thread(Dispatcher(message_fun, buffer), "thread1", 0.9)
> thread2 = Thread(Dispatcher(message_fun, buffer), "thread2", 0.9)
> thread3 = Thread(Dispatcher(message_fun, buffer), "thread3", 0.9)
> thread4 = Thread(Dispatcher(message_fun, buffer), "thread4", 0.5)
> gobject.timeout_add(100, timerfunc)
> thread1.start()
> thread2.start()
> thread3.start()
> thread4.start()
>
>
> if __name__ == "__main__":
>
> gtk.threads_init()
> window = gtk.Window(gtk.WINDOW_TOPLEVEL)
> textview = gtk.TextView()
> buffer = textview.get_buffer()
> sw = gtk.ScrolledWindow()
> sw.add(textview)
> pbar = gtk.ProgressBar()
> vbox = gtk.VBox()
> vbox.pack_start(sw)
> vbox.pack_start(pbar, False)
> window.add(vbox)
> #gui_dispatcher = Dispatcher(message_fun, buffer)
> window.connect('map_event', on_window_map_event)
> window.connect("destroy", gtk.main_quit)
> window.resize(400, 600)
> window.show_all()
> thread_finished = {"thread1":False, "thread2":False, "thread3":False, "thread4":False}
> gtk.threads_enter()
> gtk.main()
> gtk.threads_leave()
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> pygtk mailing list pygtk at daa.com.au
> http://www.daa.com.au/mailman/listinfo/pygtk
> Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/
>
More information about the pygtk
mailing list