New GitHub issue #102512 from marmarek:<br>
<hr>
<pre>
<!--
If you're new to Python and you're not sure whether what you're experiencing is a bug, the CPython issue tracker is not
the right place to seek help. Consider the following options instead:
- reading the Python tutorial: https://docs.python.org/3/tutorial/
- posting in the "Users" category on discuss.python.org: https://discuss.python.org/c/users/7
- emailing the Python-list mailing list: https://mail.python.org/mailman/listinfo/python-list
- searching our issue tracker (https://github.com/python/cpython/issues) to see if
your problem has already been reported
-->
# Bug report
`threading._shutdown()` relies on `_main_thread` having `_tstate_lock` not `None` (there is assert for that). When fork is called from a DummyThread (in my case, that's a thread created by (Py)Qt), it gets promoted to main thread, but remains very simplistic DummyThread. Especially, nobody initializes its `_tstate_lock`. `threading._after_fork()` handles the case of current thread not being in `_active` dict at all (by creating new MainThread object), but it doesn't handle the case of having DummyThread there already. This results in AssertionError in thread shutdown method - which for example confuses `multiprocessing.Process` (it gets exit code 1, even if the process function was successful).
Reproducer:
```
#!/usr/bin/python3
import threading
import multiprocessing
import _thread
class Bar(multiprocessing.Process):
def run(self):
print("process")
def run_thread(lock):
# the call to current_thread() is crucial for reproducer - it allocates
# DummyThread()
print(f"thread: {threading.current_thread()}")
p = Bar()
p.start()
p.join()
print(f"proc exit code: {p.exitcode}")
lock.release()
def main():
lock = _thread.allocate_lock()
lock.acquire()
t = _thread.start_new_thread(run_thread, (lock,))
# t.join
lock.acquire()
print(f"thread exit")
main()
```
It should print:
```
thread: <_DummyThread(Dummy-1, started daemon 135243893053120)>
process
proc exit code: 0
thread exit
```
but it prints:
```
thread: <_DummyThread(Dummy-1, started daemon 135243893053120)>
process
proc exit code: 1
thread exit
```
(see exit code difference)
`multiprocessing.Process` (or rather `multiprocessing.popen_fork.Popen._launch()` to be specific) swallows the exception, but adding some debug prints there I get:
```
Traceback (most recent call last):
File "/usr/lib64/python3.11/multiprocessing/popen_fork.py", line 71, in _launch
code = process_obj._bootstrap(parent_sentinel=child_r)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.11/multiprocessing/process.py", line 332, in _bootstrap
threading._shutdown()
File "/usr/lib64/python3.11/threading.py", line 1553, in _shutdown
assert tlock is not None
^^^^^^^^^^^^^^^^^
```
# Your environment
<!-- Include as many relevant details as possible about the environment you experienced the bug in -->
- CPython versions tested on: 3.11.2
- Operating system and architecture: Fedora 37, x86_64
</pre>
<hr>
<a href="https://github.com/python/cpython/issues/102512">View on GitHub</a>
<p>Labels: type-bug</p>
<p>Assignee: </p>