This PEP proposes a simplified API for access to the Global Interpreter Lock (GIL) for Python extension modules. Specifically, it provides a solution for authors of complex multi-threaded extensions, where the current state of Python (i.e., the state of the GIL is unknown.
This PEP proposes a new API, for platforms built with threading support, to manage the Python thread state. An implementation strategy is proposed, along with an initial, platform independent implementation.
The current Python interpreter state API is suitable for simple, single-threaded extensions, but quickly becomes incredibly complex for non-trivial, multi-threaded extensions.
Currently Python provides two mechanisms for dealing with the GIL:
For these reasons, the question of how such extensions should interact with Python is quickly becoming a FAQ. The main impetus for this PEP, a thread on python-dev [1], immediately identified the following projects with this exact issue:
Currently, there is no reasonable, portable solution to this problem, forcing each extension author to implement their own hand-rolled version. Further, the problem is complex, meaning many implementations are likely to be incorrect, leading to a variety of problems that will often manifest simply as “Python has hung”.
While the biggest problem in the existing thread-state API is the lack of the ability to query the current state of the lock, it is felt that a more complete, simplified solution should be offered to extension authors. Such a solution should encourage authors to provide error-free, complex extension modules that take full advantage of Python’s threading mechanisms.
This proposal identifies a solution for extension authors with complex multi-threaded requirements, but that only require a single “PyInterpreterState”. There is no attempt to cater for extensions that require multiple interpreter states. At the time of writing, no extension has been identified that requires multiple PyInterpreterStates, and indeed it is not clear if that facility works correctly in Python itself.
This API will not perform automatic initialization of Python, or initialize Python for multi-threaded operation. Extension authors must continue to call Py_Initialize(), and for multi-threaded applications, PyEval_InitThreads(). The reason for this is that the first thread to call PyEval_InitThreads() is nominated as the “main thread” by Python, and so forcing the extension author to specify the main thread (by requiring them to make this first call) removes ambiguity. As Py_Initialize() must be called before PyEval_InitThreads(), and as both of these functions currently support being called multiple times, the burden this places on extension authors is considered reasonable.
It is intended that this API be all that is necessary to acquire the Python GIL. Apart from the existing, standard Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS macros, it is assumed that no additional thread state API functions will be used by the extension. Extensions with such complicated requirements are free to continue to use the existing thread state API.
This proposal recommends a new API be added to Python to simplify the management of the GIL. This API will be available on all platforms built with WITH_THREAD defined.
The intent is that assuming Python has correctly been initialized, an extension author be able to use a small, well-defined “prologue dance”, at any time and on any thread, which will ensure Python is ready to be used on that thread. After the extension has finished with Python, it must also perform an “epilogue dance” to release any resources previously acquired. Ideally, these dances can be expressed in a single line.
Specifically, the following new APIs are proposed:
Common usage will be:
The general operation of PyGILState_Ensure() will be:
The general operation of PyGILState_Release() will be:
It is assumed that it is an error if two discrete PyThreadStates are used for a single thread. Comments in pystate.h (“State unique per thread”) support this view, although it is never directly stated. Thus, this will require some implementation of Thread Local Storage. Fortunately, a platform independent implementation of Thread Local Storage already exists in the Python source tree, in the SGI threading port. This code will be integrated into the platform independent Python core, but in such a way that platforms can provide a more optimal implementation if desired.
An implementation of this proposal can be found at https://bugs.python.org/issue684256
This document has been placed in the public domain.
Source: https://github.com/python/peps/blob/main/peps/pep-0311.rst
Last modified: 2025-02-01 08:59:27 UTC