From ed34cecb2e70ace5cffe6838b56b09397d0ce550 Mon Sep 17 00:00:00 2001 From: b-pass Date: Tue, 29 Jul 2025 21:03:59 -0400 Subject: [PATCH 1/2] Seems like 3.12 has concurrency issues when creating a subinterpreter, easiest workaround is just to lock during it. --- include/pybind11/subinterpreter.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/pybind11/subinterpreter.h b/include/pybind11/subinterpreter.h index 9f2f704c57..f218db2e6a 100644 --- a/include/pybind11/subinterpreter.h +++ b/include/pybind11/subinterpreter.h @@ -77,6 +77,7 @@ class subinterpreter { /// @note This function acquires (and then releases) the main interpreter GIL, but the main /// interpreter and its GIL are not required to be held prior to calling this function. static inline subinterpreter create(PyInterpreterConfig const &cfg) { + error_scope err_scope; subinterpreter result; { @@ -85,7 +86,21 @@ class subinterpreter { auto prev_tstate = PyThreadState_Get(); - auto status = Py_NewInterpreterFromConfig(&result.creation_tstate_, &cfg); + PyStatus status; + + { + /* + Several internal CPython modules are lacking proper subinterpreter support in 3.12 + even though it is "stable" in that version. This most commonly seems to cause + crashes when two interpreters concurrently initialize, which imports several things + (lke builtins, unicode, codecs). + */ +#if PY_VERSION_HEX < 0x030D0000 + static std::mutex one_at_a_time; + std::lock_guard guard(one_at_a_time); +#endif + status = Py_NewInterpreterFromConfig(&result.creation_tstate_, &cfg); + } // this doesn't raise a normal Python exception, it provides an exit() status code. if (PyStatus_Exception(status)) { @@ -117,6 +132,7 @@ class subinterpreter { // same as the default config in the python docs PyInterpreterConfig cfg; std::memset(&cfg, 0, sizeof(cfg)); + cfg.allow_threads = 1; cfg.check_multi_interp_extensions = 1; cfg.gil = PyInterpreterConfig_OWN_GIL; return create(cfg); From 78fb0e185bbe8cec9839361069309de76df5829a Mon Sep 17 00:00:00 2001 From: b-pass Date: Tue, 29 Jul 2025 21:09:02 -0400 Subject: [PATCH 2/2] Only need this for PER_INTERPRETER_GIL --- include/pybind11/subinterpreter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/pybind11/subinterpreter.h b/include/pybind11/subinterpreter.h index f218db2e6a..45396fac32 100644 --- a/include/pybind11/subinterpreter.h +++ b/include/pybind11/subinterpreter.h @@ -93,9 +93,9 @@ class subinterpreter { Several internal CPython modules are lacking proper subinterpreter support in 3.12 even though it is "stable" in that version. This most commonly seems to cause crashes when two interpreters concurrently initialize, which imports several things - (lke builtins, unicode, codecs). + (like builtins, unicode, codecs). */ -#if PY_VERSION_HEX < 0x030D0000 +#if PY_VERSION_HEX < 0x030D0000 && defined(Py_MOD_PER_INTERPRETER_GIL_SUPPORTED) static std::mutex one_at_a_time; std::lock_guard guard(one_at_a_time); #endif