aboutsummaryrefslogtreecommitdiff
path: root/docs/advanced/misc.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/advanced/misc.rst')
-rw-r--r--docs/advanced/misc.rst79
1 files changed, 71 insertions, 8 deletions
diff --git a/docs/advanced/misc.rst b/docs/advanced/misc.rst
index b3f3b226..805ec838 100644
--- a/docs/advanced/misc.rst
+++ b/docs/advanced/misc.rst
@@ -39,15 +39,42 @@ The ``PYBIND11_MAKE_OPAQUE`` macro does *not* require the above workarounds.
Global Interpreter Lock (GIL)
=============================
-When calling a C++ function from Python, the GIL is always held.
+The Python C API dictates that the Global Interpreter Lock (GIL) must always
+be held by the current thread to safely access Python objects. As a result,
+when Python calls into C++ via pybind11 the GIL must be held, and pybind11
+will never implicitly release the GIL.
+
+.. code-block:: cpp
+
+ void my_function() {
+ /* GIL is held when this function is called from Python */
+ }
+
+ PYBIND11_MODULE(example, m) {
+ m.def("my_function", &my_function);
+ }
+
+pybind11 will ensure that the GIL is held when it knows that it is calling
+Python code. For example, if a Python callback is passed to C++ code via
+``std::function``, when C++ code calls the function the built-in wrapper
+will acquire the GIL before calling the Python callback. Similarly, the
+``PYBIND11_OVERRIDE`` family of macros will acquire the GIL before calling
+back into Python.
+
+When writing C++ code that is called from other C++ code, if that code accesses
+Python state, it must explicitly acquire and release the GIL.
+
The classes :class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be
used to acquire and release the global interpreter lock in the body of a C++
function call. In this way, long-running C++ code can be parallelized using
-multiple Python threads. Taking :ref:`overriding_virtuals` as an example, this
+multiple Python threads, **but great care must be taken** when any
+:class:`gil_scoped_release` appear: if there is any way that the C++ code
+can access Python objects, :class:`gil_scoped_acquire` should be used to
+reacquire the GIL. Taking :ref:`overriding_virtuals` as an example, this
could be realized as follows (important changes highlighted):
.. code-block:: cpp
- :emphasize-lines: 8,9,31,32
+ :emphasize-lines: 8,30,31
class PyAnimal : public Animal {
public:
@@ -56,9 +83,7 @@ could be realized as follows (important changes highlighted):
/* Trampoline (need one for each virtual function) */
std::string go(int n_times) {
- /* Acquire GIL before calling Python code */
- py::gil_scoped_acquire acquire;
-
+ /* PYBIND11_OVERRIDE_PURE will acquire the GIL before accessing Python state */
PYBIND11_OVERRIDE_PURE(
std::string, /* Return type */
Animal, /* Parent class */
@@ -78,13 +103,14 @@ could be realized as follows (important changes highlighted):
.def(py::init<>());
m.def("call_go", [](Animal *animal) -> std::string {
- /* Release GIL before calling into (potentially long-running) C++ code */
+ // GIL is held when called from Python code. Release GIL before
+ // calling into (potentially long-running) C++ code
py::gil_scoped_release release;
return call_go(animal);
});
}
-The ``call_go`` wrapper can also be simplified using the `call_guard` policy
+The ``call_go`` wrapper can also be simplified using the ``call_guard`` policy
(see :ref:`call_policies`) which yields the same result:
.. code-block:: cpp
@@ -92,6 +118,34 @@ The ``call_go`` wrapper can also be simplified using the `call_guard` policy
m.def("call_go", &call_go, py::call_guard<py::gil_scoped_release>());
+Common Sources Of Global Interpreter Lock Errors
+==================================================================
+
+Failing to properly hold the Global Interpreter Lock (GIL) is one of the
+more common sources of bugs within code that uses pybind11. If you are
+running into GIL related errors, we highly recommend you consult the
+following checklist.
+
+- Do you have any global variables that are pybind11 objects or invoke
+ pybind11 functions in either their constructor or destructor? You are generally
+ not allowed to invoke any Python function in a global static context. We recommend
+ using lazy initialization and then intentionally leaking at the end of the program.
+
+- Do you have any pybind11 objects that are members of other C++ structures? One
+ commonly overlooked requirement is that pybind11 objects have to increase their reference count
+ whenever their copy constructor is called. Thus, you need to be holding the GIL to invoke
+ the copy constructor of any C++ class that has a pybind11 member. This can sometimes be very
+ tricky to track for complicated programs Think carefully when you make a pybind11 object
+ a member in another struct.
+
+- C++ destructors that invoke Python functions can be particularly troublesome as
+ destructors can sometimes get invoked in weird and unexpected circumstances as a result
+ of exceptions.
+
+- You should try running your code in a debug build. That will enable additional assertions
+ within pybind11 that will throw exceptions on certain GIL handling errors
+ (reference counting operations).
+
Binding sequence data types, iterators, the slicing protocol, etc.
==================================================================
@@ -298,6 +352,15 @@ The class ``options`` allows you to selectively suppress auto-generated signatur
m.def("add", [](int a, int b) { return a + b; }, "A function which adds two numbers");
}
+pybind11 also appends all members of an enum to the resulting enum docstring.
+This default behavior can be disabled by using the ``disable_enum_members_docstring()``
+function of the ``options`` class.
+
+With ``disable_user_defined_docstrings()`` all user defined docstrings of
+``module_::def()``, ``class_::def()`` and ``enum_()`` are disabled, but the
+function signatures and enum members are included in the docstring, unless they
+are disabled separately.
+
Note that changes to the settings affect only function bindings created during the
lifetime of the ``options`` instance. When it goes out of scope at the end of the module's init function,
the default settings are restored to prevent unwanted side effects.