1 # The following self-contained little program usually freezes with most
4 # Unhandled exception in thread:
5 # Traceback (innermost last):
6 # File "importbug.py", line 6
7 # x = whrandom.randint(1,3)
8 # AttributeError: randint
10 # Here's the program; it doesn't use anything from the attached module:
17 x
= whrandom
.randint(1,3)
20 if N
== 0: done
.release()
23 a
= thread
.allocate_lock()
24 done
= thread
.allocate_lock()
29 thread
.start_new_thread(task
, ())
34 # Sticking an acquire/release pair around the 'import' statement makes the
37 # I believe that what happens is:
39 # 1) The first thread to hit the import atomically reaches, and executes
40 # most of, get_module. In particular, it finds Lib/whrandom.pyc,
41 # installs its name in sys.modules, and executes
43 # v = eval_code(co, d, d, d, (object *)NULL);
45 # to initialize the module.
47 # 2) eval_code "ticker"-slices the 1st thread out, and gives another thread
48 # a chance. When this 2nd thread hits the same 'import', import_module
49 # finds 'whrandom' in sys.modules, so just proceeds.
51 # 3) But the 1st thread is still "in the middle" of executing whrandom.pyc.
52 # So the 2nd thread has a good chance of trying to look up 'randint'
53 # before the 1st thread has placed it in whrandom's dict.
55 # 4) The more threads there are, the more likely that at least one of them
56 # will do this before the 1st thread finishes the import work.
58 # If that's right, a perhaps not-too-bad workaround would be to introduce a
59 # static "you can't interrupt this thread" flag in ceval.c, check it before
60 # giving up interpreter_lock, and have IMPORT_NAME set it & restore (plain
61 # clearing would not work) it around its call to import_module. To its
62 # credit, there's something wonderfully perverse about fixing a race via an
63 # unprotected static <grin>.
65 # as-with-most-other-things-(pseudo-)parallel-programming's-more-fun-
66 # in-python-too!-ly y'rs - tim
68 # Tim Peters tim@ksr.com
69 # not speaking for Kendall Square Research Corp