New submission from Peter Saveliev <[email protected]>:
The _newname() function has no locking.
It is called from the new thread constructor. Such constructor is executed
within parent thread. So, when several threads create new threads
simultaneously, there can be race condition, leading to the same name for two
(or even more) threads.
8<--------------------------------
>>> import threading
>>> import dis
>>> dis.dis(threading._newname)
403 0 LOAD_GLOBAL 0 (_counter)
3 LOAD_CONST 1 (1)
6 BINARY_ADD
7 STORE_GLOBAL 0 (_counter)
404 10 LOAD_FAST 0 (template)
13 LOAD_GLOBAL 0 (_counter)
16 BINARY_MODULO
17 RETURN_VALUE
>>>
8<--------------------------------
The race condition can be achieved between BINARY_ADD and STORE_GLOBAL. Several
threads can do BINARY_ADD before the first one will do STORE_GLOBAL. All racing
threads will get the same name.
8<--------------------------------
$ for i in `seq 0 100`; do python thread_test.py |\
awk -F Thread- '{print $2}' |\
grep -vE '^$' |\
sort |\
uniq -c -d; done
2 35
2 12
...
8<--------------------------------
As you see, there are cases when several threads can get same name.
Proposals: use thread-safe increment counter (with atomic get-increment) like
itertools.counter() (that does not release GIL)
----------
components: Extension Modules
files: thread_test.py
messages: 133963
nosy: Peter.Saveliev
priority: normal
severity: normal
status: open
title: race condition in threading._newname()
type: behavior
versions: Python 2.6
Added file: http://bugs.python.org/file21704/thread_test.py
_______________________________________
Python tracker <[email protected]>
<http://bugs.python.org/issue11866>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com