diff --git a/guide/src/migration.md b/guide/src/migration.md index 8292e0054a1..dfc9bd4e406 100644 --- a/guide/src/migration.md +++ b/guide/src/migration.md @@ -206,16 +206,72 @@ PyO3 0.23 introduces preliminary support for the new free-threaded build of CPython 3.13. PyO3 features that implicitly assumed the existence of the GIL are not exposed in the free-threaded build, since they are no longer safe. -If you make use of these features then you will need to use conditional -compilation to replace them for extensions built for free-threaded -Python. Extensions built for the free-threaded build will have the -`Py_GIL_DISABLED` attribute defined. +If you make use of these features then you will need to account for the +unavailability of this API in the free-threaded build. One way to handle it is +via conditional compilation -- extensions built for the free-threaded build will +have the `Py_GIL_DISABLED` attribute defined. ### `GILProtected` `GILProtected` allows mutable access to static data by leveraging the GIL to lock concurrent access from other threads. In free-threaded python there is no -GIL, so you will need to replace this type with some other form of locking. +GIL, so you will need to replace this type with some other form of locking. In +many cases, `std::sync::Atomic` or `std::sync::Mutex` will be sufficient. If the +locks do not guard the execution of arbitrary Python code or use of the CPython +C API then conditional compilation is likely unnecessary since `GILProtected` +was not needed in the first place. + +Before: + +```rust,ignore +# use pyo3::prelude::*; +use pyo3::sync::GILProtected; +use pyo3::types::{PyDict, PyNone}; +use std::cell::RefCell; + +static OBJECTS: GILProtected>>> = + GILProtected::new(RefCell::new(Vec::new())); + +fn main() { + Python::with_gil(|py: Python| { + let d = PyDict::new(py); + // stand-in for something that executes arbitrary python code + d.set_item(PyNone::get(py), PyNone::get(py)).unwrap(); + OBJECTS.get(py).borrow_mut().push(d.unbind()); + }); +} +``` + +After: + +```rust +use pyo3::prelude::*; +#[cfg(not(Py_GIL_DISABLED))] +use pyo3::sync::GILProtected; +use pyo3::types::{PyDict, PyNone}; +#[cfg(not(Py_GIL_DISABLED))] +use std::cell::RefCell; +#[cfg(Py_GIL_DISABLED)] +use std::sync::Mutex; + +#[cfg(not(Py_GIL_DISABLED))] +static OBJECTS: GILProtected>>> = + GILProtected::new(RefCell::new(Vec::new())); +#[cfg(Py_GIL_DISABLED)] +static OBJECTS: Mutex>> = Mutex::new(Vec::new()); + +fn main() { + Python::with_gil(|py| { + let d = PyDict::new(py); + // stand-in for something that executes arbitrary python code + d.set_item(PyNone::get(py), PyNone::get(py)).unwrap(); + #[cfg(not(Py_GIL_DISABLED))] + OBJECTS.get(py).borrow_mut().push(d.unbind()); + #[cfg(Py_GIL_DISABLED)] + OBJECTS.lock().unwrap().push(d.unbind()); + }); +} +``` diff --git a/src/sync.rs b/src/sync.rs index 7a84f35b051..c7122a45976 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -19,6 +19,8 @@ use crate::PyVisit; /// It ensures that only one thread at a time can access the inner value via shared references. /// It can be combined with interior mutability to obtain mutable references. /// +/// This type is not defined for extensions built against the free-threaded CPython ABI. +/// /// # Example /// /// Combining `GILProtected` with `RefCell` enables mutable access to static data: