mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			69 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			69 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # 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
 | 
