Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/advanced/embedding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -492,4 +492,8 @@ Best Practices for sub-interpreter safety
So you must still consider the thread safety of your C++ code. Remember, in Python 3.12
sub-interpreters must be destroyed on the same thread that they were created on.

- When using sub-interpreters in free-threaded python builds, note that creating and destroying
sub-interpreters may initiate a "stop-the-world". Be sure to detach long-running C++ threads
from Python thread state (similar to releasing the GIL) to avoid deadlocks.

- Familiarize yourself with :ref:`misc_concurrency`.
18 changes: 9 additions & 9 deletions tests/test_with_catch/test_subinterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,6 @@ TEST_CASE("Single Subinterpreter") {

# if PY_VERSION_HEX >= 0x030D0000
TEST_CASE("Move Subinterpreter") {
// Test is skipped on free-threaded Python 3.14+ due to a hang in Py_EndInterpreter()
// when the subinterpreter is destroyed from a different thread than it was created on.
// See: https://github.com/pybind/pybind11/pull/5940
# if PY_VERSION_HEX >= 0x030E0000 && defined(Py_GIL_DISABLED)
PYBIND11_CATCH2_SKIP_IF(true, "Skipped on free-threaded Python 3.14+ (see PR #5940)");
# endif

std::unique_ptr<py::subinterpreter> sub(new py::subinterpreter(py::subinterpreter::create()));

// on this thread, use the subinterpreter and import some non-trivial junk
Expand All @@ -113,14 +106,21 @@ TEST_CASE("Move Subinterpreter") {
py::module_::import("external_module");
}

std::thread([&]() {
auto t = std::thread([&]() {
// Use it again
{
py::subinterpreter_scoped_activate activate(*sub);
py::module_::import("external_module");
}
sub.reset();
}).join();
});

// on 3.14.1+ destructing a sub-interpreter does a stop-the-world. we need to detach our
// thread state in order for that to be possible.
{
py::gil_scoped_release nogil;
t.join();
}

REQUIRE(!sub);

Expand Down
Loading