Added an explenation that the GIL can temporarily be released even while holding a GILGuard

This commit is contained in:
konstin 2018-08-20 22:56:24 +02:00
parent db4a2d9017
commit 82129c70b4
2 changed files with 27 additions and 4 deletions

View file

@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## Unreleased ## Unreleased
### Fixed
* Added an explenation that the GIL can temporarily be released even while holding a GILGuard.
### Removed ### Removed
* The pyobject_extract macro * The pyobject_extract macro

View file

@ -20,11 +20,30 @@ use typeob::{PyObjectAlloc, PyTypeInfo, PyTypeObject};
/// The 'Python' struct is a zero-size marker struct that is required for most Python operations. /// The 'Python' struct is a zero-size marker struct that is required for most Python operations.
/// This is used to indicate that the operation accesses/modifies the Python interpreter state, /// This is used to indicate that the operation accesses/modifies the Python interpreter state,
/// and thus can only be called if the Python interpreter is initialized and the /// and thus can only be called if the Python interpreter is initialized and the
/// Python global interpreter lock (GIL) is acquired. /// Python global interpreter lock (GIL) is acquired. The lifetime `'p` represents the lifetime of
/// The lifetime `'p` represents the lifetime of the Python interpreter. /// the Python interpreter.
/// ///
/// You can imagine the GIL to be a giant `Mutex<PythonInterpreterState>`. /// Note that the GIL can be temporarily released by the python interpreter during a function call
/// The type `Python<'p>` then acts like a reference `&'p PythonInterpreterState`. /// (e.g. importing a module), even when you're holding a GILGuard. In general, you don't need to
/// worry about this becauseas the GIL is reaquired before returning to the rust code:
///
/// ```text
/// GILGuard |=====================================|
/// GIL actually held |==========| |================|
/// Rust code running |=======| |==| |======|
/// ```
///
/// This behaviour can cause deadlocks when trying to lock while holding a GILGuard:
///
/// * Thread 1 acquires the GIL
/// * Thread 1 locks a mutex
/// * Thread 1 makes a call into the python interpreter, which releases the GIL
/// * Thread 2 acquires the GIL
/// * Thraed 2 tries to locks the mutex, blocks
/// * Thread 1's python interpreter call blocks trying to reacquire the GIL held by thread 2
///
/// To avoid deadlocking, you should release the GIL before trying to lock a mutex, e.g. with
/// [Python::allow_threads].
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Python<'p>(PhantomData<&'p GILGuard>); pub struct Python<'p>(PhantomData<&'p GILGuard>);