-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
os.fork()
called from DummyThread confuses threading shutdown logic
#102512
Comments
Simplified reproducer (not importing multiprocessing, but doing what it does directly):
It fails this way:
|
If os.fork() is called from a DummyThread (a thread started not by the threading module, in which somebody called threading.current_thread()), it becomes main thread. Threading shutdown logic relies on the main thread having tstate_lock, so initialize it for the DummyThread too. Fixes python#102512
If os.fork() is called from a DummyThread (a thread started not by the threading module, in which somebody called threading.current_thread()), it becomes main thread. Threading shutdown logic relies on the main thread having tstate_lock, so initialize it for the DummyThread too. Fixes python#102512
The bug causes occasional issues with multi-process pipeline executions with pytest using concurrent running. This is a known issue (python/cpython#102512) which will eventually be fixed in Python, at that time the patch should become no-op and can be removed.
@marmarek Do you have enough of a handle on the problem to propose a PR that fixes it? |
I already did, over half a year ago (it's linked in the issue description). Should I rebase it to get it merged? |
My bad! I stumbled upon this thread and didn't notice that (I blame GitHub :-). It needs to be reviewed, perhaps by @serhiy-storchaka. |
Would not be more correct to replace the current |
…from a foreign thread (GH-113261) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
…alled from a foreign thread (pythonGH-113261) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. (cherry picked from commit 49785b0) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
…ork() called from a foreign thread (pythonGH-113261) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. (cherry picked from commit 49785b0) Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
…ork() called from a foreign thread (pythonGH-113261) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. (cherry picked from commit 49785b0) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
Thank you for your report and PR @marmarek. I created a more radical PR based on it. It is not only create a lock for a main thread after fork, it makes it non-demonic and changes it type. Perhaps a similar should be done for normal threads, but this is a different issue. It can be an instance of a custom Thread subclass, so changing its type may be not safe. |
…called from a foreign thread (GH-113261) (GH-114431) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. (cherry picked from commit 49785b0) Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
…alled from a foreign thread (pythonGH-113261) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. (cherry picked from commit 49785b0) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
…called from a foreign thread (GH-113261) (GH-114430) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. (cherry picked from commit 49785b0) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
…alled from a foreign thread (pythonGH-113261) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
…alled from a foreign thread (pythonGH-113261) Always set a _MainThread as a main thread after os.fork() is called from a thread started not by the threading module. A new _MainThread was already set as a new main thread after fork if threading.current_thread() was not called for a foreign thread before fork. Now, if it was called before fork, the implicitly created _DummyThread will be turned into _MainThread after fork. It fixes, in particularly, an incompatibility of _DummyThread with the threading shutdown logic which relies on the main thread having tstate_lock. Co-authored-by: Marek Marczykowski-Górecki <[email protected]>
Bug report
threading._shutdown()
relies on_main_thread
having_tstate_lock
notNone
(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 confusesmultiprocessing.Process
(it gets exit code 1, even if the process function was successful).Reproducer:
It should print:
but it prints:
(see exit code difference)
multiprocessing.Process
(or rathermultiprocessing.popen_fork.Popen._launch()
to be specific) swallows the exception, but adding some debug prints there I get:Your environment
Linked PRs
The text was updated successfully, but these errors were encountered: