On Feb 20, 2011, at 10:09 PM, Robert Schroll wrote: > On 02/20/2011 03:08 PM, Stephen Langer wrote: >> This is what we do: >> >> class IdleBlockCallback: >> def __init__(self, func, args=(), kwargs={}): >> self.func = func >> self.args = args >> self.kwargs = kwargs >> self.event = threading.Event() >> self.result = None >> def __call__(self): >> gtk.gdk.threads_enter() >> try: >> self.result = self.func(*self.args, **self.kwargs) >> finally: >> gtk.gdk.flush() >> gtk.gdk.threads_leave() >> self.event.set() >> return False # don't repeat >> >> def runBlock(func, args=(), kwargs={}): >> callbackobj = OOFIdleBlockCallback(func, args, kwargs) >> callbackobj.event.clear() >> gobject.idle_add(callbackobj, priority=gobject.PRIORITY_LOW) >> callbackobj.event.wait() >> return callbackobj.result >> > > Thank you, thank you, thank you - this is exactly what I was looking > for. For some reason, I didn't think to look in Python's threading > module. Two questions: > > 1) Since all GTK stuff is happening in the mainloop thread, I'm only > calling gobject.threads_init(), not gtk.gdk.threads_init() (as suggested > here: http://library.gnome.org/devel/gtk-faq/stable/x499.html) Am I > correct in understanding that I don't need to call > gtk.gdk.threads_enter() and _leave() in the callback? (I've taken them > out, and nothing seemed to break.)
My impression is that they're required within idle callbacks. > What about the flush()? It's probably to prevent race conditions in our code, but I don't remember the specific reason. > 2) I'd like to use this code in a project to be released under the BSD > license. Is that okay with you? Sure. It's from the NIST OOF project, http://www.ctcms.nist.gov/oof/oof2, which is not copyrighted. > >> Call runBlock on the worker thread. Be sure that you're really on the >> worker thread, because if you call it on the main thread it will hang. > > If I understand things correctly (unlikely), gobject.main_depth() will > be greater than zero in the main loop thread and zero in the worker > threads. (At least if I only start the main loop in one thread.) So > I've written this function to ensure code is called in the main loop. > Limited testing suggests it's working. > > def run_in_main_loop(func, *args, **kwargs): > if gobject.main_depth(): > # In the main loop already > return func(*args, **kwargs) > callbackobj = IdleBlockCallback(func, args, kwargs) > callbackobj.event.clear() > gobject.idle_add(callbackobj, priority=gobject.PRIORITY_LOW) > callbackobj.event.wait() > return callbackobj.result I haven't used main_depth. We do a similar thing with a different mechanism. Each thread has a unique id which can be compared to the main thread's id to see if the function is being called by the main thread. -- Steve -- -- stephen.lan...@nist.gov Tel: (301) 975-5423 -- -- http://math.nist.gov/mcsd/Staff/SLanger/ Fax: (301) 975-3553 -- -- NIST, 100 Bureau Drive, Stop 8910, Gaithersburg, Md 20899-8910 -- -- "I don't think this will work. That's why it's science." -- -- Naomi Langer (age 6), 17 Feb 2003 -- _______________________________________________ pygtk mailing list pygtk@daa.com.au http://www.daa.com.au/mailman/listinfo/pygtk Read the PyGTK FAQ: http://faq.pygtk.org/