1 #!/usr/bin/env python2.5
3 # Copyright (c) 2011 Neal H. Walfield <neal@walfield.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 logger = logging.getLogger(__name__)
23 _run_in_main_thread = None
26 def init(run_in_main_thread=None):
28 run_in_main_thread is a function that takes a single argument, a
29 callable and returns False. run_in_main_thread should run the
30 function in the main thread.
32 If you are using glib, gobject.idle_add (the default) is
33 sufficient. (gobject.idle_add is thread-safe.)
35 if run_in_main_thread is None:
37 run_in_main_thread = gobject.idle_add
39 global _run_in_main_thread
40 assert _run_in_main_thread is None
41 _run_in_main_thread = run_in_main_thread
44 _main_thread = threading.currentThread ()
46 def execute(func, *args, **kwargs):
48 Execute FUNC in the main thread.
50 If kwargs['async'] exists and is True, the function is executed
51 asynchronously (i.e., the thread does not wait for the function to
52 return in which case the function's return value is discarded).
53 Otherwise, this function waits until the function is executed and
54 returns its return value.
58 async = kwargs['async']
63 if threading.currentThread() == _main_thread:
66 func (*args, **kwargs)
68 logger.debug("mainthread.execute: Executing %s: %s"
69 % (func, traceback.format_exc ()))
72 return func (*args, **kwargs)
74 assert _run_in_main_thread is not None, \
75 "You can't call this function from a non-main thread until you've called init()"
78 cond = threading.Condition()
81 result['done'] = False
85 # Execute the function.
86 assert threading.currentThread() == _main_thread
89 result['result'] = func (*args, **kwargs)
91 logger.debug("mainthread.execute: Executing %s: %s"
92 % (func, traceback.format_exc ()))
106 _run_in_main_thread (doit())
109 # Don't wait for the method to complete execution.
112 # Wait for the result to become available.
113 while not result['done']:
116 return result.get ('result', None)
118 if __name__ == "__main__":
124 def in_main_thread(test_num):
125 assert threading.currentThread() == _main_thread, \
126 "Test %d failed" % (test_num,)
129 mainloop = gobject.MainLoop()
130 gobject.threads_init()
132 assert execute (in_main_thread, 1) == 1
133 assert (execute (in_main_thread, 2, async=False) == 2)
134 execute (in_main_thread, 3, async=True)
136 class T(threading.Thread):
138 threading.Thread.__init__(self)
141 assert threading.currentThread() != _main_thread
143 assert execute (in_main_thread, 4) == 4
144 assert (execute (in_main_thread, 5, async=False) == 5)
145 execute (in_main_thread, 6, async=True)
146 execute (mainloop.quit, async=False)
153 gobject.idle_add (start_thread)
157 def wrapper(*args, **kwargs):
158 return execute (f, *args, **kwargs)