STINNER Victor <vstin...@redhat.com> added the comment:
threading._shutdown() uses threading.enumerate() which iterations on threading._active. threading.Thread registers itself into threading._active using its _bootstrap_inner() method. It unregisters itself when _bootstrap_inner() completes, whereas its is_alive() method still returns true: since the underlying native thread still runs and the Python thread state still exists. _thread._set_sentinel() creates a lock and registers a tstate->on_delete callback to release this lock. It's called by threading.Thread._set_tstate_lock() to set threading.Thread._tstate_lock. This lock is used by threading.Thread.join() to wait until the thread completes. _thread.start_new_thread() calls the C function t_bootstrap() which ends with: tstate->interp->num_threads--; PyThreadState_Clear(tstate); PyThreadState_DeleteCurrent(); PyThread_exit_thread(); _PyThreadState_DeleteCurrent() calls tstate->on_delete() which releases threading.Thread._tstate_lock lock. In test_threads_join_2() test, PyThreadState_Clear() blocks on clearing thread variables: the Sleeper destructor of the Sleeper instance sleeps. The race condition is that: * threading._shutdown() rely on threading._alive * Py_EndInterpreter() rely on the interpreter linked list of Python thread states: interp->tstate_head. ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue36402> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com