diff options
author | Guido van Rossum <guido@python.org> | 1994-05-16 09:35:22 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1994-05-16 09:35:22 (GMT) |
commit | 48a69b70b21b83bccfbbb209590fee8323500d90 (patch) | |
tree | 68b65828229182bf6402e7d64224835e629e7329 /Demo/threads/bug.py | |
parent | 9f2a5b0f665530bc37c5c94e6ae5bc860f527635 (diff) | |
download | cpython-48a69b70b21b83bccfbbb209590fee8323500d90.zip cpython-48a69b70b21b83bccfbbb209590fee8323500d90.tar.gz cpython-48a69b70b21b83bccfbbb209590fee8323500d90.tar.bz2 |
Initial revision
Diffstat (limited to 'Demo/threads/bug.py')
-rw-r--r-- | Demo/threads/bug.py | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/Demo/threads/bug.py b/Demo/threads/bug.py new file mode 100644 index 0000000..5860536 --- /dev/null +++ b/Demo/threads/bug.py @@ -0,0 +1,69 @@ +# The following self-contained little program usually freezes with most +# threads reporting +# +# Unhandled exception in thread: +# Traceback (innermost last): +# File "importbug.py", line 6 +# x = whrandom.randint(1,3) +# AttributeError: randint +# +# Here's the program; it doesn't use anything from the attached module: + +import thread + +def task(): + global N + import whrandom + x = whrandom.randint(1,3) + a.acquire() + N = N - 1 + if N == 0: done.release() + a.release() + +a = thread.allocate_lock() +done = thread.allocate_lock() +N = 10 + +done.acquire() +for i in range(N): + thread.start_new_thread(task, ()) +done.acquire() +print 'done' + + +# Sticking an acquire/release pair around the 'import' statement makes the +# problem go away. +# +# I believe that what happens is: +# +# 1) The first thread to hit the import atomically reaches, and executes +# most of, get_module. In particular, it finds Lib/whrandom.pyc, +# installs its name in sys.modules, and executes +# +# v = eval_code(co, d, d, d, (object *)NULL); +# +# to initialize the module. +# +# 2) eval_code "ticker"-slices the 1st thread out, and gives another thread +# a chance. When this 2nd thread hits the same 'import', import_module +# finds 'whrandom' in sys.modules, so just proceeds. +# +# 3) But the 1st thread is still "in the middle" of executing whrandom.pyc. +# So the 2nd thread has a good chance of trying to look up 'randint' +# before the 1st thread has placed it in whrandom's dict. +# +# 4) The more threads there are, the more likely that at least one of them +# will do this before the 1st thread finishes the import work. +# +# If that's right, a perhaps not-too-bad workaround would be to introduce a +# static "you can't interrupt this thread" flag in ceval.c, check it before +# giving up interpreter_lock, and have IMPORT_NAME set it & restore (plain +# clearing would not work) it around its call to import_module. To its +# credit, there's something wonderfully perverse about fixing a race via an +# unprotected static <grin>. +# +# as-with-most-other-things-(pseudo-)parallel-programming's-more-fun- +# in-python-too!-ly y'rs - tim +# +# Tim Peters tim@ksr.com +# not speaking for Kendall Square Research Corp |