Spec-Zone.ru › Python 3.14

Примитивы синхронизации

C-API предоставляет базовую блокировку взаимного исключения.

type PyMutex

Блокировка взаимного исключения. PyMutex следует инициализировать нулём, чтобы представить состояние без блокировки. Например:

PyMutex mutex = {0};

Экземпляры PyMutex не следует копировать или перемещать. И содержимое, и адрес PyMutex имеют значение; объект должен находиться в неизменном доступном для записи участке памяти.

Примечание

В настоящее время PyMutex занимает один байт, однако его размер следует считать нестабильным. В будущих выпусках Python размер может измениться без периода устаревания.

Добавлено в версии 3.13.

void PyMutex_Lock(PyMutex *m)
Потокобезопасность: Атомарная.

Блокирует мьютекс m. Если другой поток уже заблокировал его, вызывающий поток будет ждать, пока мьютекс не будет разблокирован. Во время ожидания поток временно отсоединяет состояние потока, если оно существует.

Добавлено в версии 3.13.

void PyMutex_Unlock(PyMutex *m)
Потокобезопасность: Атомарная.

Разблокирует мьютекс m. Мьютекс должен быть заблокирован — в противном случае функция вызовет фатальную ошибку.

Добавлено в версии 3.13.

int PyMutex_IsLocked(PyMutex *m)
Потокобезопасность: Атомарная.

Возвращает ненулевое значение, если мьютекс m в данный момент заблокирован, и ноль в противном случае.

Примечание

Эта функция предназначена только для использования в утверждениях и при отладке. Не используйте её для принятия решений об управлении параллелизмом, поскольку состояние блокировки может измениться сразу после проверки.

Добавлено в версии 3.14.

API критических секций Python

API критических секций предоставляет уровень защиты от взаимных блокировок поверх блокировок отдельных объектов для свободнопоточной версии CPython. Он предназначен для замены зависимости от глобальной блокировки интерпретатора и ничего не делает в версиях Python с глобальной блокировкой интерпретатора.

Критические секции предназначены для пользовательских типов, реализованных в расширениях C-API. Как правило, их не следует использовать со встроенными типами, такими как list и dict, поскольку их общедоступные C-API уже используют критические секции внутри. Заметное исключение — PyDict_Next(), для которого критическую секцию необходимо открыть извне.

Критические секции предотвращают взаимные блокировки, неявно приостанавливая активные критические секции; поэтому они не обеспечивают монопольный доступ, как традиционные блокировки, например PyMutex. При начале критической секции захватывается блокировка отдельного объекта. Если код, выполняемый внутри критической секции, вызывает функции C-API, он может приостановить критическую секцию и тем самым освободить блокировку объекта, чтобы другие потоки могли захватить блокировку того же объекта.

Также доступны варианты, принимающие указатели PyMutex вместо объектов Python. Используйте эти варианты, чтобы начать критическую секцию в ситуации, когда PyObject отсутствует — например, при работе с типом C, который не наследует PyObject и не оборачивает его, но всё же должен вызывать C-API способом, который может привести к взаимным блокировкам.

Функции и структуры, используемые макросами, доступны в случаях, когда макросы C недоступны. Их следует использовать только так, как показано в раскрытии соответствующих макросов. Обратите внимание: размеры и содержимое структур могут измениться в будущих версиях Python.

Примечание

Операции, которым необходимо одновременно заблокировать два объекта, должны использовать Py_BEGIN_CRITICAL_SECTION2. Нельзя использовать вложенные критические секции для одновременной блокировки нескольких объектов, поскольку внутренняя критическая секция может приостановить внешние. Этот API не позволяет блокировать одновременно более двух объектов.

Пример использования:

static PyObject *
set_field(MyObject *self, PyObject *value)
{
   Py_BEGIN_CRITICAL_SECTION(self);
   Py_SETREF(self->field, Py_XNewRef(value));
   Py_END_CRITICAL_SECTION();
   Py_RETURN_NONE;
}

В приведённом выше примере Py_SETREF вызывает Py_DECREF, которая может вызвать произвольный код через функцию освобождения объекта. API критических секций предотвращает потенциальные взаимные блокировки из-за повторного входа и порядка захвата блокировок, позволяя среде выполнения временно приостановить критическую секцию, если код, вызванный финализатором, блокируется и вызывает PyEval_SaveThread().

Py_BEGIN_CRITICAL_SECTION(op)

Захватывает блокировку отдельного объекта op и начинает критическую секцию.

В сборке без GIL этот макрос раскрывается в:

{
    PyCriticalSection _py_cs;
    PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))

В сборке по умолчанию этот макрос раскрывается в {.

Добавлено в версии 3.13.

Py_BEGIN_CRITICAL_SECTION_MUTEX(m)

Блокирует мьютекс m и начинает критическую секцию.

В сборке без GIL этот макрос раскрывается в:

{
     PyCriticalSection _py_cs;
     PyCriticalSection_BeginMutex(&_py_cs, m)

Обратите внимание: в отличие от Py_BEGIN_CRITICAL_SECTION, аргумент макроса не приводится к другому типу — это должен быть указатель PyMutex.

В сборке по умолчанию этот макрос раскрывается в {.

Добавлено в версии 3.14.

Py_END_CRITICAL_SECTION()

Завершает критическую секцию и освобождает блокировку отдельного объекта.

В сборке без GIL этот макрос раскрывается в:

    PyCriticalSection_End(&_py_cs);
}

В сборке по умолчанию этот макрос раскрывается в }.

Добавлено в версии 3.13.

Py_BEGIN_CRITICAL_SECTION2(a, b)

Захватывает блокировки отдельных объектов a и b и начинает критическую секцию. Блокировки захватываются в фиксированном порядке (сначала по наименьшему адресу), чтобы избежать взаимных блокировок из-за порядка захвата.

В сборке без GIL этот макрос раскрывается в:

{
    PyCriticalSection2 _py_cs2;
    PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))

В сборке по умолчанию этот макрос раскрывается в {.

Добавлено в версии 3.13.

Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2)

Блокирует мьютексы m1 и m2 и начинает критическую секцию.

В сборке без GIL этот макрос раскрывается в:

{
     PyCriticalSection2 _py_cs2;
     PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)

Обратите внимание: в отличие от Py_BEGIN_CRITICAL_SECTION2, аргументы макроса не приводятся к другому типу — это должны быть указатели PyMutex.

В сборке по умолчанию этот макрос раскрывается в {.

Добавлено в версии 3.14.

Py_END_CRITICAL_SECTION2()

Завершает критическую секцию и освобождает блокировки отдельных объектов.

В сборке без GIL этот макрос раскрывается в:

    PyCriticalSection2_End(&_py_cs2);
}

В сборке по умолчанию этот макрос раскрывается в }.

Добавлено в версии 3.13.

Устаревшие API блокировок

Эти API считаются устаревшими начиная с Python 3.13 в связи с появлением PyMutex.

type PyThread_type_lock

Указатель на блокировку взаимного исключения.

type PyLockStatus

Результат захвата блокировки с тайм-аутом.

enumerator PY_LOCK_FAILURE

Не удалось захватить блокировку.

enumerator PY_LOCK_ACQUIRED

Блокировка успешно захвачена.

enumerator PY_LOCK_INTR

Блокировка была прервана сигналом.

PyThread_type_lock PyThread_allocate_lock(void)
Часть стабильного ABI.

Выделяет новую блокировку.

В случае успеха эта функция возвращает блокировку; в случае ошибки она возвращает 0, не устанавливая исключение.

Вызывающему не требуется удерживать присоединённое состояние потока.

void PyThread_free_lock(PyThread_type_lock lock)
Часть стабильного ABI.

Уничтожает lock. При вызове этой функции ни один поток не должен удерживать блокировку.

Вызывающему не требуется удерживать присоединённое состояние потока.

PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag)
Часть стабильного ABI.

Захватывает lock с тайм-аутом.

Функция будет ждать microseconds микросекунд, пытаясь захватить блокировку. Если время ожидания истечёт, функция вернёт PY_LOCK_FAILURE. Если microseconds равно -1, ожидание продолжится до тех пор, пока блокировка не будет освобождена.

Если intr_flag равно 1, попытка захватить блокировку может быть прервана сигналом; в этом случае функция вернёт PY_LOCK_INTR. После прерывания обычно ожидается, что вызывающий код вызовет Py_MakePendingCalls(), чтобы передать исключение коду Python.

Если блокировка успешно захвачена, функция вернёт PY_LOCK_ACQUIRED.

Вызывающему не требуется удерживать присоединённое состояние потока.

int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
Часть стабильного ABI.

Захватывает lock.

Если waitflag равно 1 и блокировку в данный момент удерживает другой поток, функция будет ждать, пока блокировку можно будет захватить, и всегда вернёт 1.

Если waitflag равно 0 и блокировку удерживает другой поток, функция не будет ждать и вместо этого вернёт 0. Если блокировку не удерживает ни один другой поток, функция захватит её и вернёт 1.

В отличие от PyThread_acquire_lock_timed(), попытка захватить блокировку не может быть прервана сигналом.

Вызывающему не требуется удерживать присоединённое состояние потока.

int PyThread_release_lock(PyThread_type_lock lock)
Часть стабильного ABI.

Освобождает lock. Если блокировка lock не удерживается, функция вызовет фатальную ошибку.

Вызывающему не требуется удерживать присоединённое состояние потока.

© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/c-api/synchronization.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API