[Tutor] Threads, locking and race condition

Jeff Shannon jeff@ccvcorp.com
Thu Jan 16 13:58:36 2003


Branimir Petrovic wrote:

>- Say Thread-3 needs to access its storage and calls the function:
>
>	def get_thread_storage():
>		thread_id = thread.get_ident()
>		tss = _tss.get(thread_id)
>
>At this very point having reached its 10-th byte code instruction,
>Thread-3 is suspended, so that other threads will get their chance
>to run.
>
>- By pure chance/coincidence Thread-6 is awaken, and being just
>about to call get_thread_storage() - this time it calls it indeed,
>and not only that it calls the function, but also it manages to exit
>from it by the time Thread-6 'fades' and goes to forced 'sleep',
>
>- By another remarkable turn of events, Thread-3 is awaken again,
>only to find variable tss that is now pointing to a value set by run of
>interrupting Tread-6. Thread-3 will not have slightest 'clue' that its
>own value was overwritten 'behind its back' while its execution was
>suspended. As a result Thread-3 will now return wrong dictionary?
>

No, it won't.  Each thread will have a different thread id, so the 
results of _tss.get(thread_id) will be different for each thread.  But 
the tss variable that it's being stored in is a local variable -- it's 
only valid within that specific function.  When Thread 6 runs through 
get_thread_storage(), it does so in a separate execution frame that is 
completely separate from Thread 3's execution frame, and therefore it 
cannot touch the local variables in Thread 3's execution frame.

Note, however, that the thread module is very low-level.  For writing 
actual application code, you're *much* better off using the higher-level 
threading module, which is built on top of the thread module.  In 
particular, threading offers the Thread class, which makes many things 
much simpler.  By using the Thread class and the Queue module, it's 
possible to create multithreaded applications without needing to worry 
nearly as much about contention and deadlock issues.  I do realize that 
you're looking at the Cookbook code for educational purposes, and that's 
fine -- it's good to try to understand the lower-level aspects -- but 
it's also good to know that, at some point, you can trust that someone 
else has taken care of the details and you don't need to worry about it.  :)

Jeff Shannon
Technician/Programmer
Credit International



>
>Do I see the problem that does not exist? If you spot anything wrong
>with my (contrived?) assumption/scenario - please let me know.
>
>
>
>Let's examine other option:
>
>- Say we change function in such a way as to obtain lock with very
>first step into the function:
>
>	def get_thread_storage():
>		tss_lock.acquire()
>		thread_id = thread.get_ident()
>
>#	...and so on ending with:
>
>			finally:
>				_tss_lock.release()
>
>		return tss
>
>Is it possible that Thread-3 does its job and release the lock object,
>but just before returning tss - scheduler suspends it and run Thread-6
>that calls the function, and manages to finish it and exit the
>function? Wouldn't Thread-3 if awaken now return the tss as left by
>Thread-6?
>
>The way I see two proposed scenarios - both are possible, second one
>less but nevertheless - still possible. Given long enough time - 
>'mishap' will happen for sure. Right or wrong?
>
>Which brings me to next nagging question:
>- How 'granular' are Python's byte code instructions?
>Is this:	
>	thread_id = thread.get_ident() 
>one byte code instruction or more than one byte code instruction?
>
>To slightly re-phrase the question:
>- Is the 'line' of code (such as thread_id = thread.get_ident()) 
>guaranteed to execute and fully finish before Python switches to
>another thread or not?
>
>- If 'yes' is answer to the above question, what would happen in 
>this (admittedly - artificial) case:
>
>	return choice and [yes][0] or [no][0]
>
>How many byte codes would that be?
>
>- And what about:
>	return mySillyChoice() and toughChoiceA() or toughChoiceB()
>
>This will 'break' (be switched) at any convenient spot in any of three
>function calls yes/no?
>
>I would very much like to hear back (hopefully) on any of outlined
>questions.
>
>If you as far as this line, thanks for your patience.
>
>Branimir
>
>_______________________________________________
>Tutor maillist  -  Tutor@python.org
>http://mail.python.org/mailman/listinfo/tutor
>
>  
>