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
--
-- [email protected] 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 [email protected]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/