Документация Python неофициальный перевод

synchronization.md

261 строк · 18.1 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3/c-api/synchronization.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Примитивы синхронизации89C-API предоставляет базовую блокировку взаимного исключения.1011#### `type PyMutex`1213Блокировка взаимного исключения. `PyMutex` следует инициализировать нулём для представления разблокированного состояния. Например:1415```c16PyMutex mutex = {0};17```1819Экземпляры `PyMutex` не должны копироваться или перемещаться. Как содержимое, так и адрес `PyMutex` имеют смысл, и он должен оставаться в фиксированном, доступном для записи месте в памяти.2021> **Примечание**22>23> `PyMutex` в настоящее время занимает один байт, но размер следует считать нестабильным. Размер может измениться в будущих выпусках Python без периода устаревания.2425Добавлено в версии 3.13.2627#### `void PyMutex_Lock(PyMutex *m)`2829*Потокобезопасность: [атомарно](https://python-all.ru/3/library/threadsafety.html#threadsafety-level-atomic).*3031Блокирует мьютекс *m*. Если другой поток уже заблокировал его, вызывающий поток будет блокироваться до разблокировки мьютекса. На время блокировки поток временно отсоединит [состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state), если оно существует.3233Добавлено в версии 3.13.3435#### `void PyMutex_Unlock(PyMutex *m)`3637*Потокобезопасность: [атомарно](https://python-all.ru/3/library/threadsafety.html#threadsafety-level-atomic).*3839Разблокирует мьютекс *m*. Мьютекс должен быть заблокирован – в противном случае функция выдаст фатальную ошибку.4041Добавлено в версии 3.13.4243#### `int PyMutex_IsLocked(PyMutex *m)`4445*Потокобезопасность: [атомарно](https://python-all.ru/3/library/threadsafety.html#threadsafety-level-atomic).*4647Возвращает ненулевое значение, если мьютекс *m* в данный момент заблокирован, и ноль в противном случае.4849> **Примечание**50>51> Эта функция предназначена только для использования в утверждениях и отладке и не должна использоваться для принятия решений по управлению параллелизмом, так как состояние блокировки может измениться сразу после проверки.5253Добавлено в версии 3.14.5455## API критических секций Python5657API критических секций предоставляет уровень предотвращения взаимных блокировок поверх объектных блокировок для [свободно-поточного](https://python-all.ru/3/glossary.html#term-free-threading) CPython. Они предназначены для замены зависимости от [глобальной блокировки интерпретатора](https://python-all.ru/3/glossary.html#term-global-interpreter-lock) и являются пустышками (no-op) в версиях Python с глобальной блокировкой интерпретатора.5859Критические секции предназначены для использования с пользовательскими типами, реализованными в расширениях C-API. Их обычно не следует использовать со встроенными типами, такими как [`list`](https://python-all.ru/3/library/stdtypes.html#list) и [`dict`](https://python-all.ru/3/library/stdtypes.html#dict), поскольку их публичные C-API уже внутренне используют критические секции, за заметным исключением [`PyDict_Next()`](https://python-all.ru/3/c-api/dict.html#c.PyDict_Next), для которого требуется внешнее получение критической секции.6061Критические секции предотвращают взаимные блокировки, неявно приостанавливая активные критические секции, поэтому они не предоставляют исключительный доступ, как традиционные блокировки, например [`PyMutex`](https://python-all.ru/3/c-api/synchronization.html#c.PyMutex). При запуске критической секции захватывается объектная блокировка для данного объекта. Если код, выполняемый внутри критической секции, вызывает функции C-API, то он может приостановить критическую секцию, тем самым освободив объектную блокировку, так что другие потоки смогут захватить объектную блокировку для того же объекта.6263Также доступны варианты, принимающие указатели [`PyMutex`](https://python-all.ru/3/c-api/synchronization.html#c.PyMutex) вместо объектов Python. Используйте эти варианты для запуска критической секции в ситуации, когда нет [`PyObject`](https://python-all.ru/3/c-api/structures.html#c.PyObject) – например, при работе с типом C, который не расширяет и не оборачивает `PyObject`, но всё равно нуждается в вызове C-API способом, который может привести к взаимным блокировкам.6465Функции и структуры, используемые макросами, предоставлены для случаев, когда макросы C недоступны. Их следует использовать только так, как в соответствующих развёртках макросов. Учтите, что размеры и содержимое структур могут измениться в будущих версиях Python.6667> **Примечание**68>69> Операции, которым необходимо заблокировать два объекта одновременно, должны использовать [`Py_BEGIN_CRITICAL_SECTION2`](https://python-all.ru/3/c-api/synchronization.html#c.Py_BEGIN_CRITICAL_SECTION2). *Нельзя* использовать вложенные критические секции для блокировки более одного объекта одновременно, поскольку внутренняя критическая секция может приостановить внешние критические секции. Этот API не предоставляет способа заблокировать более двух объектов одновременно.7071Пример использования:7273```c74static PyObject *75set_field(MyObject *self, PyObject *value)76{77   Py_BEGIN_CRITICAL_SECTION(self);78   Py_SETREF(self->field, Py_XNewRef(value));79   Py_END_CRITICAL_SECTION();80   Py_RETURN_NONE;81}82```8384В приведённом выше примере [`Py_SETREF`](https://python-all.ru/3/c-api/refcounting.html#c.Py_SETREF) вызывает [`Py_DECREF`](https://python-all.ru/3/c-api/refcounting.html#c.Py_DECREF), который может вызывать произвольный код через функцию освобождения объекта. API критических секций избегает потенциальных взаимных блокировок из-за повторного входа и порядка блокировок, позволяя среде выполнения временно приостанавливать критическую секцию, если код, запущенный финализатором, блокируется и вызывает [`PyEval_SaveThread()`](https://python-all.ru/3/c-api/threads.html#c.PyEval_SaveThread).8586#### `Py_BEGIN_CRITICAL_SECTION(op)`8788Захватывает объектную блокировку для объекта *op* и начинает критическую секцию.8990В сборке free-threaded этот макрос раскрывается в:9192```c93{94    PyCriticalSection _py_cs;95    PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))96```9798В сборке по умолчанию этот макрос раскрывается в `{`.99100Добавлено в версии 3.13.101102#### `Py_BEGIN_CRITICAL_SECTION_MUTEX(m)`103104Блокирует мьютекс *m* и начинает критическую секцию.105106В сборке free-threaded этот макрос раскрывается в:107108```c109{110     PyCriticalSection _py_cs;111     PyCriticalSection_BeginMutex(&_py_cs, m)112```113114Обратите внимание, что в отличие от [`Py_BEGIN_CRITICAL_SECTION`](https://python-all.ru/3/c-api/synchronization.html#c.Py_BEGIN_CRITICAL_SECTION), для аргумента макроса нет приведения – это должен быть указатель на [`PyMutex`](https://python-all.ru/3/c-api/synchronization.html#c.PyMutex).115116В сборке по умолчанию этот макрос раскрывается в `{`.117118Добавлено в версии 3.14.119120#### `Py_END_CRITICAL_SECTION()`121122Завершает критическую секцию и освобождает блокировку объекта.123124В сборке free-threaded этот макрос раскрывается в:125126```c127    PyCriticalSection_End(&_py_cs);128}129```130131В сборке по умолчанию этот макрос раскрывается в `}`.132133Добавлено в версии 3.13.134135#### `Py_BEGIN_CRITICAL_SECTION2(a, b)`136137Захватывает блокировки объектов для объектов *a* и *b* и начинает критическую секцию. Блокировки захватываются в одном порядке (сначала наименьший адрес), чтобы избежать взаимоблокировок из-за порядка захвата.138139В сборке free-threaded этот макрос раскрывается в:140141```c142{143    PyCriticalSection2 _py_cs2;144    PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))145```146147В сборке по умолчанию этот макрос раскрывается в `{`.148149Добавлено в версии 3.13.150151#### `Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2)`152153Блокирует мьютексы *m1* и *m2* и начинает критическую секцию.154155В сборке free-threaded этот макрос раскрывается в:156157```c158{159     PyCriticalSection2 _py_cs2;160     PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)161```162163Обратите внимание, что в отличие от [`Py_BEGIN_CRITICAL_SECTION2`](https://python-all.ru/3/c-api/synchronization.html#c.Py_BEGIN_CRITICAL_SECTION2), для аргументов макроса не требуется приведение типов – они должны быть указателями [`PyMutex`](https://python-all.ru/3/c-api/synchronization.html#c.PyMutex).164165В сборке по умолчанию этот макрос раскрывается в `{`.166167Добавлено в версии 3.14.168169#### `Py_END_CRITICAL_SECTION2()`170171Завершает критическую секцию и освобождает блокировки объектов.172173В сборке free-threaded этот макрос раскрывается в:174175```c176    PyCriticalSection2_End(&_py_cs2);177}178```179180В сборке по умолчанию этот макрос раскрывается в `}`.181182Добавлено в версии 3.13.183184## Устаревшие API блокировок185186Эти API устарели с Python 3.13 с введением [`PyMutex`](https://python-all.ru/3/c-api/synchronization.html#c.PyMutex).187188#### `type PyThread_type_lock`189190Указатель на блокировку взаимного исключения.191192#### `type PyLockStatus`193194Результат захвата блокировки с таймаутом.195196#### `enumerator PY_LOCK_FAILURE`197198Не удалось захватить блокировку.199200#### `enumerator PY_LOCK_ACQUIRED`201202Блокировка успешно захвачена.203204#### `enumerator PY_LOCK_INTR`205206Захват блокировки прерван сигналом.207208#### `PyThread_type_lock PyThread_allocate_lock(void)`209210*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*211212Выделить новую блокировку.213214В случае успеха функция возвращает блокировку; в случае неудачи возвращает `0` без установленного исключения.215216Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).217218#### `void PyThread_free_lock(PyThread_type_lock lock)`219220*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*221222Уничтожить *блокировку*. Блокировка не должна удерживаться ни одним потоком при вызове этой функции.223224Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).225226#### `PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag)`227228*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*229230Захватить *блокировку* с таймаутом.231232Будет ожидать *microseconds* микросекунд для захвата блокировки. Если таймаут истекает, функция возвращает [`PY_LOCK_FAILURE`](https://python-all.ru/3/c-api/synchronization.html#c.PY_LOCK_FAILURE). Если *microseconds* равно `-1`, будет ожидать неопределённо долго, пока блокировка не будет освобождена.233234Если *intr\_flag* равно `1`, захват блокировки может быть прерван сигналом, и в этом случае функция возвращает [`PY_LOCK_INTR`](https://python-all.ru/3/c-api/synchronization.html#c.PY_LOCK_INTR). После прерывания ожидается, что вызывающая сторона вызовет [`Py_MakePendingCalls()`](https://python-all.ru/3/c-api/threads.html#c.Py_MakePendingCalls) для передачи исключения в код Python.235236Если блокировка успешно захвачена, функция возвращает [`PY_LOCK_ACQUIRED`](https://python-all.ru/3/c-api/synchronization.html#c.PY_LOCK_ACQUIRED).237238Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).239240#### `int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)`241242*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*243244Захватить *блокировку*.245246Если *waitflag* равно `1`, и другой поток в данный момент удерживает блокировку, эта функция будет ждать, пока блокировка не будет захвачена, и всегда будет возвращать `1`.247248Если *waitflag* равно `0`, и другой поток удерживает блокировку, эта функция не будет ждать, а вернёт `0`. Если блокировка не удерживается никаким другим потоком, то эта функция захватит её и вернёт `1`.249250В отличие от [`PyThread_acquire_lock_timed()`](https://python-all.ru/3/c-api/synchronization.html#c.PyThread_acquire_lock_timed), захват блокировки не может быть прерван сигналом.251252Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).253254#### `int PyThread_release_lock(PyThread_type_lock lock)`255256*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*257258Освободить *блокировку*. Если *блокировка* не удерживается, то эта функция вызовет фатальную ошибку.259260Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).261