> **Источник:** https://python-all.ru/3.15/c-api/threads.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# Состояния потоков и глобальная блокировка интерпретатора

За исключением [сборки со свободной многопоточностью](https://python-all.ru/3.15/glossary.html#term-free-threaded-build) [CPython](https://python-all.ru/3.15/glossary.html#term-CPython), интерпретатор Python в целом не является потокобезопасным. Для поддержки многопоточных программ на Python существует глобальная блокировка, называемая [глобальной блокировкой интерпретатора](https://python-all.ru/3.15/glossary.html#term-global-interpreter-lock), или [GIL](https://python-all.ru/3.15/glossary.html#term-GIL), которую поток должен захватить перед доступом к объектам Python. Без этой блокировки даже простейшие операции могут вызвать проблемы в многопоточной программе: например, если два потока одновременно увеличивают счётчик ссылок одного и того же объекта, счётчик может увеличиться только один раз вместо двух.

Таким образом, только поток, удерживающий GIL, может работать с объектами Python или вызывать C API Python.

Для эмуляции параллелизма интерпретатор регулярно пытается переключать потоки между инструкциями байт-кода (см. [`sys.setswitchinterval()`](https://python-all.ru/3.15/library/sys.html#sys.setswitchinterval)). Поэтому блокировки также необходимы для потокобезопасности в коде на чистом Python.

Кроме того, глобальная блокировка интерпретатора освобождается вокруг блокирующих операций ввода-вывода, таких как чтение или запись в файл. В C API это делается с помощью [отсоединения состояния потока](https://python-all.ru/3.15/c-api/threads.html#detaching-thread-state).

Интерпретатор Python хранит некоторую локальную для потока информацию внутри структуры данных, называемой [`PyThreadState`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState), известной как [состояние потока](https://python-all.ru/3.15/glossary.html#term-thread-state). Каждый поток имеет указатель, локальный для потока, на `PyThreadState`; состояние потока, на которое ссылается этот указатель, считается [присоединённым](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

Поток может иметь только одно [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) в каждый момент времени. Присоединённое состояние потока обычно аналогично удержанию GIL, за исключением сборок со свободной многопоточностью. В сборках с включённым GIL присоединение состояния потока будет блокироваться до тех пор, пока не будет получен GIL. Однако даже в сборках с отключённым GIL всё равно требуется иметь присоединённое состояние потока, поскольку интерпретатору необходимо отслеживать, какие потоки могут обращаться к объектам Python.

> **Примечание**
>
> Даже в сборке со свободной многопоточностью присоединение состояния потока может блокироваться, так как GIL может быть повторно включён, или потоки могут быть временно приостановлены (например, во время сборки мусора).

Обычно при использовании C API Python всегда есть присоединённое состояние потока, в том числе при встраивании и реализации методов, так что необходимость самостоятельно настраивать состояние потока возникает редко. Только в некоторых особых случаях, например в блоке [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) или в новом потоке, поток не будет иметь присоединённого состояния потока. Если есть сомнения, проверьте, возвращает ли [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_GetUnchecked) `NULL`.

Если всё же необходимо создать состояние потока, рекомендуется использовать [`PyThreadState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_EnsureFromView), которые управляют состоянием потока.

## Отсоединение состояния потока из кода расширения

Большая часть кода расширения, работающего с [состоянием потока](https://python-all.ru/3.15/glossary.html#term-thread-state), имеет следующую простую структуру:

```c
Save the thread state in a local variable.
... Do some blocking I/O operation ...
Restore the thread state from the local variable.
```

Это настолько распространено, что существует пара макросов для упрощения:

```c
Py_BEGIN_ALLOW_THREADS
... Do some blocking I/O operation ...
Py_END_ALLOW_THREADS
```

Макрос [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) открывает новый блок и объявляет скрытую локальную переменную; макрос [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_END_ALLOW_THREADS) закрывает блок.

Приведённый выше блок раскрывается в следующий код:

```c
PyThreadState *_save;

_save = PyEval_SaveThread();
... Do some blocking I/O operation ...
PyEval_RestoreThread(_save);
```

Вот как работают эти функции:

Присоединённое состояние потока подразумевает, что GIL удерживается для интерпретатора. Чтобы отсоединить его, вызывается [`PyEval_SaveThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_SaveThread), и результат сохраняется в локальной переменной.

Отсоединяя состояние потока, GIL освобождается, что позволяет другим потокам присоединиться к интерпретатору и выполняться, пока текущий поток выполняет блокирующий ввод-вывод. Когда операция ввода-вывода завершается, старое состояние потока повторно присоединяется вызовом [`PyEval_RestoreThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_RestoreThread), который будет ожидать, пока не удастся захватить GIL.

> **Примечание**
>
> Выполнение блокирующего ввода-вывода – самый распространённый случай применения отсоединения состояния потока, но его также полезно вызывать в длительном нативном коде, которому не нужен доступ к объектам Python или C API Python. Например, стандартные модули [`zlib`](https://python-all.ru/3.15/library/zlib.html#module-zlib) и [`hashlib`](https://python-all.ru/3.15/library/hashlib.html#module-hashlib) отсоединяют [состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) при сжатии или хешировании данных.

В [сборке со свободной многопоточностью](https://python-all.ru/3.15/glossary.html#term-free-threaded-build) [GIL](https://python-all.ru/3.15/glossary.html#term-GIL) обычно не рассматривается, но **отсоединение состояния потока всё равно требуется**, потому что интерпретатору периодически нужно блокировать все потоки для получения согласованного представления объектов Python без риска состояний гонки. Например, CPython в настоящее время приостанавливает все потоки на короткое время во время работы сборщика мусора.

> **Предупреждение**
>
> Отсоединение состояния потока может привести к неожиданному поведению во время завершения работы интерпретатора. См. раздел [Предостережения относительно завершения работы интерпретатора](https://python-all.ru/3.15/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization) для получения более подробной информации.

### API

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

> **Примечание**
>
> Эти макросы всё ещё необходимы в [сборке со свободной многопоточностью](https://python-all.ru/3.15/glossary.html#term-free-threaded-build) для предотвращения взаимоблокировок.

#### `Py_BEGIN_ALLOW_THREADS`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Этот макрос раскрывается в `{ PyThreadState *_save; _save = PyEval_SaveThread();`. Обратите внимание, что он содержит открывающую фигурную скобку; она должна быть сопоставлена с последующим макросом [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_END_ALLOW_THREADS). См. выше дополнительное обсуждение этого макроса.

#### `Py_END_ALLOW_THREADS`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Этот макрос раскрывается в `PyEval_RestoreThread(_save); }`. Обратите внимание, что он содержит закрывающую фигурную скобку; она должна быть сопоставлена с предыдущим макросом [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS). См. выше дополнительное обсуждение этого макроса.

#### `Py_BLOCK_THREADS`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Этот макрос разворачивается в `PyEval_RestoreThread(_save);`: он эквивалентен [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_END_ALLOW_THREADS) без закрывающей фигурной скобки.

#### `Py_UNBLOCK_THREADS`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Этот макрос разворачивается в `_save = PyEval_SaveThread();`: он эквивалентен [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) без открывающей фигурной скобки и объявления переменной.

## Использование C API из внешних потоков

Когда потоки создаются с помощью специальных Python API (таких как модуль [`threading`](https://python-all.ru/3.15/library/threading.html#module-threading)), состояние потока автоматически связывается с ними. Однако, когда поток создается из нативного кода (например, сторонней библиотекой с собственным управлением потоками), он не имеет прикрепленного состояния потока.

Если нужно вызвать код Python из этих потоков (часто это будет частью колбэк-API, предоставляемого вышеупомянутой сторонней библиотекой), необходимо сначала зарегистрировать эти потоки в интерпретаторе, создав новое состояние потока и прикрепив его.

Самый простой способ сделать это – через [`PyThreadState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_EnsureFromView).

> **Примечание**
>
> Эти функции требуют аргумент, указывающий на нужный интерпретатор; такой указатель можно получить вызовом [`PyInterpreterGuard_FromCurrent()`](https://python-all.ru/3.15/c-api/interp-lifecycle.html#c.PyInterpreterGuard_FromCurrent) (для `PyThreadState_Ensure`) или [`PyInterpreterView_FromCurrent()`](https://python-all.ru/3.15/c-api/interp-lifecycle.html#c.PyInterpreterView_FromCurrent) (для `PyThreadState_EnsureFromView`) из функции, создающей поток. Если указатель недоступен (например, когда заданная нативная библиотека потоков не предоставляет аргумент data), можно использовать [`PyInterpreterView_FromMain()`](https://python-all.ru/3.15/c-api/interp-lifecycle.html#c.PyInterpreterView_FromMain) для получения представления главного интерпретатора, но учтите, что это сделает код несовместимым с субинтерпретаторами.

Например:

```c
// Возвращаемое значение PyInterpreterGuard_FromCurrent() из
// функции, создавшей этот поток.
PyInterpreterGuard *guard = thread_data->guard;

// Создаёт новое состояние потока для интерпретатора.
PyThreadStateToken *token = PyThreadState_Ensure(guard);
if (token == NULL) {
   PyInterpreterGuard_Close(guard);
   return;
}

// Имеется корректное состояние потока – выполните здесь действия Python.
result = CallSomeFunction();
// Вычислить результат или обработать исключения.

// Освободить состояние потока. Вызовы C API не допускаются после этой
// точки.
PyThreadState_Release(token);
PyInterpreterGuard_Close(guard);
```

Имейте в виду, что вызов `PyThreadState_Ensure` не всегда создает новое состояние потока, а вызов `PyThreadState_Release` не всегда его отсоединяет. Эти функции могут повторно использовать существующее прикрепленное состояние потока или повторно прикрепить состояние потока, которое ранее было прикреплено для текущего потока.

> **См. также**
>
> [**PEP 788**](https://python-all.ru/3.15/c-api/threads.html)

### Повторное использование состояния потока при многократных вызовах

Создание и уничтожение [`PyThreadState`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState) небесплатно и стоит дороже на [сборке со свободными потоками](https://python-all.ru/3.15/glossary.html#term-free-threaded-build). Внешний поток, много раз вызывающий интерпретатор – например, рабочий поток в нативном пуле потоков – должен избегать создания нового состояния потока при каждом входе и уничтожения его при каждом выходе. Вместо этого следует настроить одно состояние потока при запуске потока (или лениво при его первом вызове в Python), прикреплять и отсоединять его вокруг каждого вызова и один раз уничтожить, когда поток завершается.

Управляйте состоянием потока явно с помощью [`PyThreadState_New()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_New), прикрепляя и отсоединяя его с помощью [`PyEval_RestoreThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_RestoreThread) и [`PyEval_SaveThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_SaveThread). Это происходит в три отдельных этапа, в разные моменты жизни потока.

Когда поток запускается, создайте одно состояние потока для него. `interp` – это целевой интерпретатор, захваченный кодом, создавшим этот поток, пока у него было прикрепленное состояние потока (например, через [`PyInterpreterState_Get()`](https://python-all.ru/3.15/c-api/subinterpreters.html#c.PyInterpreterState_Get)):

```c
PyThreadState *tstate = PyThreadState_New(interp);
```

Затем при каждом вызове Python – который может происходить много раз в течение жизни потока – прикрепите состояние потока, выполните вызовы C API Python, требующие его, и снова отсоедините, чтобы поток не удерживал GIL, когда занимается не-Python работой:

```c
PyEval_RestoreThread(tstate);
result = CallSomeFunction();  /* Здесь размещаются ваши вызовы Python C API. */
PyEval_SaveThread();
```

Когда поток завершит вызовы в Python, уничтожьте состояние потока один раз:

```c
PyEval_RestoreThread(tstate);
PyThreadState_Clear(tstate);
PyThreadState_DeleteCurrent();
```

Универсальные точки входа для вызова из внешнего потока – [`PyThreadState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Ensure) и старая [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure) – *не* гарантируют постоянное состояние потока: время жизни их состояния потока намеренно определено реализацией, поэтому пара acquire/release может создавать и уничтожать состояние потока каждый раз. Используйте [`PyThreadState_New()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_New), как показано здесь, когда необходимо повторно использовать одно состояние потока при вызовах.

Код, создавший внешний поток, должен организовать выполнение последовательности завершения до выхода потока и до вызова [`Py_FinalizeEx()`](https://python-all.ru/3.15/c-api/interp-lifecycle.html#c.Py_FinalizeEx). Если сначала начнется финализация интерпретатора, вызов shutdown [`PyEval_RestoreThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_RestoreThread) зависнет, а не вернется (см. [Предостережения относительно финализации интерпретатора](https://python-all.ru/3.15/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization)). Если поток завершится без выполнения последовательности завершения, состояние потока будет утечено на оставшееся время процесса.

### Прикрепление/отсоединение состояний потоков

#### `PyThreadStateToken *PyThreadState_Ensure(PyInterpreterGuard *guard)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) начиная с версии 3.15.*

Гарантирует, что поток имеет прикрепленное состояние потока для интерпретатора, защищенного *guard*, и поэтому может безопасно вызывать этот интерпретатор.

Вызов этой функции допустим, если поток уже имеет прикрепленное состояние потока, при условии, что последует вызов [`PyThreadState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Release), соответствующий этому (то есть разрешены “вложенные” вызовы этой функции).

Эффект функции (если он есть) будет отменен соответствующим вызовом [`PyThreadState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Release).

В случае ошибки эта функция возвращает `NULL` *без* установленного исключения. Не вызывайте `PyThreadState_Release()` в этом случае.

При успехе эта функция возвращает значение указателя, которое должно быть передано в соответствующий вызов `PyThreadState_Release()`.

Условия, при которых эта функция создает новое [состояние потока](https://python-all.ru/3.15/glossary.html#term-thread-state), считаются нестабильными и зависящими от реализации. Если необходимо управлять точным временем жизни состояния потока, рассмотрите использование [`PyThreadState_New()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_New). Однако не избегайте этой функции только на том основании, что время жизни состояния потока может быть несовместимым между версиями; изменения в этой функции будут проводиться с осторожностью и обратно совместимым образом. В частности, сохранение локальных переменных потока и аналогичного состояния будет сохранено между версиями Python.

**Деталь реализации CPython:** Точное поведение относительно того, создает ли эта функция новое состояние потока, описано ниже, но имейте в виду, что это может измениться в будущем.

Сначала функция проверяет, присутствует ли прикрепленное состояние потока. Если да, функция проверяет, совпадает ли интерпретатор этого состояния потока с интерпретатором, защищенным *guard*. Если это так, функция просто помечает состояние потока как используемое вызовом `PyThreadState_Ensure` и возвращается.

Если прикрепленного состояния потока нет, функция проверяет, использовалось ли какое-либо состояние потока текущим потоком ОС. (Это возвращается [`PyGILState_GetThisThreadState()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_GetThisThreadState).) Если да, функция проверяет, совпадает ли интерпретатор этого состояния потока с *guard*. Если совпадает, оно повторно прикрепляется и помечается как используемое.

В противном случае, если оба вышеуказанных случая не сработали, создается новое состояние потока для *guard*. Затем оно прикрепляется и помечается как принадлежащее `PyThreadState_Ensure`.

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

#### `PyThreadStateToken *PyThreadState_EnsureFromView(PyInterpreterView *view)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) начиная с версии 3.15.*

Получить присоединённое состояние потока для интерпретатора, на который ссылается *view*.

Поведение и возвращаемое значение такие же, как для [`PyThreadState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Ensure); дополнительно, если функция завершается успешно, интерпретатор, на который ссылается *view*, будет неявно защищён. Защита будет снята при соответствующем вызове [`PyThreadState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Release).

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

#### `void PyThreadState_Release(PyThreadStateToken *token)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) начиная с версии 3.15.*

Отменить вызов [`PyThreadState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_EnsureFromView).

Эта функция должна вызываться ровно один раз для каждого успешного вызова *Ensure*, при этом *token* должен быть установлен в возвращаемое значение этого вызова.

Состояние, которое было присоединено до соответствующего вызова *Ensure* (если таковое имелось), будет присоединено снова, когда [`PyThreadState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Release) вернёт управление.

Точное поведение того, удаляет ли эта функция состояние потока, считается нестабильным и зависит от реализации.

**Особенность реализации CPython:** В настоящее время эта функция уменьшает внутренний счётчик присоединённого состояния потока. Если этот счётчик когда-либо опускается ниже нуля, функция вызывает фатальную ошибку (через [`Py_FatalError()`](https://python-all.ru/3.15/c-api/sys.html#c.Py_FatalError)).

Если присоединённое состояние потока принадлежит `PyThreadState_Ensure`, то оно будет освобождено и удалено, когда внутренний счётчик достигнет нуля. В противном случае при достижении счётчиком нуля ничего не происходит.

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

#### `type PyThreadStateToken`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) (как непрозрачная структура) начиная с версии 3.15.*

Непрозрачный токен, полученный из вызова [`PyThreadState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Ensure) и переданный в соответствующий вызов [`PyThreadState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Release).

## API состояния GIL

Следующие API в целом несовместимы с подынтерпретаторами и приведут к зависанию процесса во время финализации интерпретатора (см. [Предостережения относительно финализации интерпретатора](https://python-all.ru/3.15/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization)). Поэтому эти API были [мягко устарели](https://python-all.ru/3.15/glossary.html#term-soft-deprecated) в Python 3.15 в пользу [новых API](https://python-all.ru/3.15/c-api/threads.html#c-api-foreign-threads).

#### `type PyGILState_STATE`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Тип значения, возвращаемого [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure) и передаваемого в [`PyGILState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Release).

#### `enumerator PyGILState_LOCKED`

GIL уже был захвачен, когда была вызвана [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure).

#### `enumerator PyGILState_UNLOCKED`

GIL не был захвачен, когда была вызвана [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure).

#### `PyGILState_STATE PyGILState_Ensure()`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Гарантирует, что текущий поток готов вызывать Python C API независимо от текущего состояния Python или [присоединённого состояния потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state). Эта функция может вызываться потоком сколько угодно раз, при условии, что каждый вызов сопровождается вызовом [`PyGILState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Release). В целом, другие потоковые API могут использоваться между вызовами [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure) и `PyGILState_Release()`, если состояние потока восстанавливается в предыдущее состояние до вызова Release(). Например, обычное использование макросов [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) и [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_END_ALLOW_THREADS) допустимо.

Возвращаемое значение – это непрозрачный «дескриптор» [присоединённого состояния потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) на момент вызова [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure), и его необходимо передать в [`PyGILState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Release), чтобы гарантировать, что Python останется в том же состоянии. Несмотря на то, что рекурсивные вызовы разрешены, эти дескрипторы *нельзя* совместно использовать – каждый уникальный вызов `PyGILState_Ensure()` должен сохранить дескриптор для своего вызова `PyGILState_Release()`.

После возврата функции будет существовать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state), и поток сможет вызывать произвольный код Python.

У этой функции нет способа вернуть ошибку. Поэтому ошибки либо фатальны (то есть они отправляют `SIGABRT` и аварийно завершают процесс; см. [`Py_FatalError()`](https://python-all.ru/3.15/c-api/sys.html#c.Py_FatalError)), либо поток будет заблокирован бессрочно (например, во время финализации интерпретатора).

> **Предупреждение**
>
> Вызов этой функции во время финализации интерпретатора приведёт к бесконечному зависанию потока, что может вызвать взаимоблокировки. [Предостережения относительно финализации интерпретатора](https://python-all.ru/3.15/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization) для подробностей.
>
> Кроме того, эта функция в целом не работает с подынтерпретаторами при использовании из внешних потоков, так как у неё нет способа узнать, какой интерпретатор создал поток (и поэтому она неявно выбирает главный интерпретатор).

Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.

[Мягко устарело](https://python-all.ru/3.15/glossary.html#term-soft-deprecated) начиная с версии 3.15: Используйте [`PyThreadState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_EnsureFromView) вместо него.

#### `void PyGILState_Release(PyGILState_STATE)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Освобождает все ранее приобретённые ресурсы. После этого вызова состояние Python будет таким же, как до соответствующего вызова [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure) (но обычно это состояние неизвестно вызывающей стороне, поэтому и используется API состояния GIL).

Каждый вызов [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure) должен сопровождаться вызовом [`PyGILState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Release) в том же потоке.

[Мягко устарело](https://python-all.ru/3.15/glossary.html#term-soft-deprecated) начиная с версии 3.15: Вместо этого используйте [`PyThreadState_Release()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Release).

#### `PyThreadState *PyGILState_GetThisThreadState()`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Получить [состояние потока](https://python-all.ru/3.15/glossary.html#term-thread-state), которое последним было [присоединено](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) для этого потока. (Если последнее состояние потока было удалено, эта функция возвращает `NULL`.)

Если у вызывающего есть присоединённое состояние потока, оно возвращается.

Другими словами, эта функция возвращает состояние потока, которое будет использовано [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure). Если она возвращает `NULL`, то `PyGILState_Ensure` создаёт новое состояние потока.

Эта функция не может завершиться с ошибкой.

[Мягко устарело](https://python-all.ru/3.15/glossary.html#term-soft-deprecated) начиная с версии 3.15: Вместо этого используйте [`PyThreadState_Get()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Get) или [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_GetUnchecked).

#### `int PyGILState_Check()`

Возвращает `1`, если текущий поток имеет [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state), которое совпадает с состоянием потока, возвращаемым [`PyGILState_GetThisThreadState()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_GetThisThreadState). Если у вызывающего нет присоединённого состояния потока или оно не совпадает, то возвращается `0`.

Если текущий процесс Python когда-либо создавал суб-интерпретатор, эта функция будет *всегда* возвращать `1`.

Это в основном вспомогательная/диагностическая функция.

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

[Мягко устарело](https://python-all.ru/3.15/glossary.html#term-soft-deprecated) начиная с версии 3.15: Вместо этого используйте `PyThreadState_GetUnchecked() != NULL`.

## Предостережения относительно fork()

Ещё одна важная особенность потоков – их поведение при вызове C `fork()`. На большинстве систем с `fork()` после fork процесса остаётся только тот поток, который вызвал fork. Это оказывает конкретное влияние как на обработку блокировок, так и на всё сохранённое состояние в среде выполнения CPython.

Тот факт, что остаётся только «текущий» поток, означает, что любые блокировки, удерживаемые другими потоками, никогда не будут освобождены. Python решает эту проблему для [`os.fork()`](https://python-all.ru/3.15/library/os.html#os.fork), захватывая блокировки, которые он использует внутренне, перед fork и освобождая их после. Кроме того, он сбрасывает все [объекты блокировки](https://python-all.ru/3.15/library/threading.html#lock-objects) в дочернем процессе. При расширении или встраивании Python нет способа сообщить Python о дополнительных (не-Python) блокировках, которые необходимо захватить перед fork или сбросить после него. Для достижения того же эффекта потребуется использовать системные механизмы, такие как `pthread_atfork()`. Кроме того, при расширении или встраивании Python вызов `fork()` напрямую, а не через `os.fork()` (и возврат к вызову Python) может привести к взаимоблокировке из-за того, что одна из внутренних блокировок Python удерживается потоком, который становится недействительным после fork. [`PyOS_AfterFork_Child()`](https://python-all.ru/3.15/c-api/sys.html#c.PyOS_AfterFork_Child) пытается сбросить необходимые блокировки, но не всегда может это сделать.

Тот факт, что все остальные потоки исчезают, также означает, что состояние среды выполнения CPython должно быть правильно очищено, что и делает [`os.fork()`](https://python-all.ru/3.15/library/os.html#os.fork). Это означает завершение всех остальных объектов [`PyThreadState`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState), принадлежащих текущему интерпретатору, и всех остальных объектов [`PyInterpreterState`](https://python-all.ru/3.15/c-api/subinterpreters.html#c.PyInterpreterState). Из-за этого и особой природы [«главного» интерпретатора](https://python-all.ru/3.15/c-api/subinterpreters.html#sub-interpreter-support), `fork()` следует вызывать только в «главном» потоке этого интерпретатора, где изначально была инициализирована глобальная среда выполнения CPython. Единственное исключение – если `exec()` будет вызван сразу после.

## Высокоуровневые API

Это наиболее часто используемые типы и функции при написании многопоточных расширений на C.

#### `type PyThreadState`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) (как непрозрачная структура).*

Эта структура данных представляет состояние одного потока. Единственный открытый элемент данных:

#### `PyInterpreterState *interp`

Состояние интерпретатора этого потока.

#### `void PyEval_InitThreads()`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Устаревшая функция, которая ничего не делает.

В Python 3.6 и старше эта функция создавала GIL, если его не существовало.

Изменено в версии 3.9: Теперь функция ничего не делает.

Изменено в версии 3.7: Теперь эта функция вызывается [`Py_Initialize()`](https://python-all.ru/3.15/c-api/interp-lifecycle.html#c.Py_Initialize), так что вам больше не нужно вызывать её самостоятельно.

Изменено в версии 3.2: Эту функцию больше нельзя вызывать до [`Py_Initialize()`](https://python-all.ru/3.15/c-api/interp-lifecycle.html#c.Py_Initialize).

Устарело с версии 3.9.

#### `PyThreadState *PyEval_SaveThread()`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Отсоединить [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) и вернуть его. После возврата у потока не будет [состояния потока](https://python-all.ru/3.15/glossary.html#term-thread-state).

#### `void PyEval_RestoreThread(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Установить [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) в *tstate*. Переданное [состояние потока](https://python-all.ru/3.15/glossary.html#term-thread-state) **не должно** быть присоединённым, иначе произойдёт взаимоблокировка. *tstate* будет присоединён после возврата.

> **Примечание**
>
> Вызов этой функции из потока во время завершения работы среды выполнения приведёт к зависанию потока до выхода программы, даже если поток не был создан Python. Подробнее см. [Предостережения относительно завершения интерпретатора](https://python-all.ru/3.15/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).

Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.

#### `PyThreadState *PyThreadState_Get()`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Возвращает [прикреплённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state). Если у потока нет прикреплённого состояния потока (например, при нахождении внутри блока [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.15/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS)), то возникает фатальная ошибка (поэтому вызывающему коду не нужно проверять `NULL`).

См. также [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_GetUnchecked).

#### `PyThreadState *PyThreadState_GetUnchecked()`

Аналогично [`PyThreadState_Get()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Get), но не завершает процесс фатальной ошибкой, если значение равно NULL. Вызывающий код должен самостоятельно проверить, не является ли результат NULL.

Добавлено в версии 3.13: В версиях Python с 3.5 по 3.12 эта функция была приватной и называлась `_PyThreadState_UncheckedGet()`.

#### `PyThreadState *PyThreadState_Swap(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Устанавливает [прикреплённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) равным *tstate* и возвращает [состояние потока](https://python-all.ru/3.15/glossary.html#term-thread-state), которое было прикреплено до вызова.

Эту функцию можно безопасно вызывать без [прикреплённого состояния потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state); она просто вернёт `NULL`, указывая, что предыдущего состояния потока не было.

> **См. также**
>
> [`PyEval_ReleaseThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_ReleaseThread)

> **Примечание**
>
> Аналогично [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure), эта функция приведёт к зависанию потока, если среда выполнения завершает работу.

## Низкоуровневые API

#### `PyThreadState *PyThreadState_New(PyInterpreterState *interp)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Создаёт новый объект состояния потока, принадлежащий указанному объекту интерпретатора. [Прикреплённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) не требуется.

#### `void PyThreadState_Clear(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Сбрасывает всю информацию в объекте [состояния потока](https://python-all.ru/3.15/glossary.html#term-thread-state). *tstate* должно быть [прикреплено](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

Изменено в версии 3.9: Теперь эта функция вызывает колбэк `PyThreadState.on_delete`. Ранее это происходило в [`PyThreadState_Delete()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Delete).

Изменено в версии 3.13: Колбэк `PyThreadState.on_delete` удалён.

#### `void PyThreadState_Delete(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Уничтожает объект [состояния потока](https://python-all.ru/3.15/glossary.html#term-thread-state). *tstate* не должно быть [прикреплено](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) ни к какому потоку. *tstate* должно быть предварительно сброшено вызовом [`PyThreadState_Clear()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Clear).

#### `void PyThreadState_DeleteCurrent(void)`

Открепляет [прикреплённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) (которое должно быть предварительно сброшено вызовом [`PyThreadState_Clear()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_Clear)) и затем уничтожает его.

После возврата никакое [состояние потока](https://python-all.ru/3.15/glossary.html#term-thread-state) не будет [прикреплено](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

#### `PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) начиная с версии 3.10.*

Возвращает текущий кадр состояния потока Python *tstate*.

Возвращает [сильную ссылку](https://python-all.ru/3.15/glossary.html#term-strong-reference). Возвращает `NULL`, если в данный момент кадр не выполняется.

См. также [`PyEval_GetFrame()`](https://python-all.ru/3.15/c-api/reflection.html#c.PyEval_GetFrame).

*tstate* не должен быть `NULL` и должен быть [прикреплён](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

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

#### `uint64_t PyThreadState_GetID(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) начиная с версии 3.10.*

Возвращает уникальный [идентификатор состояния потока](https://python-all.ru/3.15/glossary.html#term-thread-state) для состояния потока Python *tstate*.

*tstate* не должен быть `NULL` и должен быть [прикреплён](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

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

#### `PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) начиная с версии 3.10.*

Возвращает интерпретатор состояния потока Python *tstate*.

*tstate* не должен быть `NULL` и должен быть [прикреплён](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

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

#### `void PyThreadState_EnterTracing(PyThreadState *tstate)`

Приостанавливает трассировку и профилирование в состоянии потока Python *tstate*.

Возобновляет их с помощью функции [`PyThreadState_LeaveTracing()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_LeaveTracing).

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

#### `void PyThreadState_LeaveTracing(PyThreadState *tstate)`

Возобновляет трассировку и профилирование в состоянии потока Python *tstate*, приостановленные функцией [`PyThreadState_EnterTracing()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_EnterTracing).

См. также функции [`PyEval_SetTrace()`](https://python-all.ru/3.15/c-api/profiling.html#c.PyEval_SetTrace) и [`PyEval_SetProfile()`](https://python-all.ru/3.15/c-api/profiling.html#c.PyEval_SetProfile).

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

#### `int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size)`

> *Это [нестабильное API](https://python-all.ru/3.15/c-api/stable.html#unstable-c-api). Оно может меняться без предупреждения в минорных версиях.*

Устанавливает начальный адрес защиты стека и размер защиты стека состояния потока Python.

В случае успеха возвращает `0`. В случае неудачи устанавливает исключение и возвращает `-1`.

CPython реализует [контроль рекурсии](https://python-all.ru/3.15/c-api/exceptions.html#recursion) для кода на C, вызывая [`RecursionError`](https://python-all.ru/3.15/library/exceptions.html#RecursionError), когда замечает, что стек выполнения машины близок к переполнению. См., например, функцию [`Py_EnterRecursiveCall()`](https://python-all.ru/3.15/c-api/exceptions.html#c.Py_EnterRecursiveCall). Для этого ему нужно знать расположение стека текущего потока, которое он обычно получает от операционной системы. При изменении стека, например, с помощью методов переключения контекста, таких как `boost::context` библиотеки Boost, необходимо вызвать [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3.15/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection), чтобы сообщить CPython об изменении.

Необходимо вызвать [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3.15/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection) либо до, либо после изменения стека. Не следует вызывать другие функции Python C API между этим вызовом и изменением стека.

Для отмены этой операции см. [`PyUnstable_ThreadState_ResetStackProtection()`](https://python-all.ru/3.15/c-api/threads.html#c.PyUnstable_ThreadState_ResetStackProtection).

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

#### `void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)`

> *Это [нестабильное API](https://python-all.ru/3.15/c-api/stable.html#unstable-c-api). Оно может меняться без предупреждения в минорных версиях.*

Сбрасывает начальный адрес защиты стека и размер защиты стека состояния потока Python в значения по умолчанию операционной системы.

Пояснение см. в [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3.15/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection).

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

#### `PyObject *PyThreadState_GetDict()`

*Возвращаемое значение: заимствованная ссылка.*

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Возвращает словарь, в котором расширения могут хранить информацию о состоянии, специфичном для потока. Каждое расширение должно использовать уникальный ключ для хранения состояния в словаре. Эту функцию можно вызывать, когда [состояние потока](https://python-all.ru/3.15/glossary.html#term-thread-state) не [прикреплено](https://python-all.ru/3.15/glossary.html#term-attached-thread-state). Если эта функция возвращает `NULL`, никакое исключение не было возбуждено, и вызывающий должен считать, что состояние потока не прикреплено.

#### `void PyEval_AcquireThread(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

[Прикрепляет](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) *tstate* к текущему потоку, который не должен быть `NULL` или уже прикреплён.

Вызывающий поток не должен уже иметь [прикреплённого состояния потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

> **Примечание**
>
> Вызов этой функции из потока во время завершения работы среды выполнения приведёт к зависанию потока до выхода программы, даже если поток не был создан Python. Подробнее см. [Предостережения относительно завершения интерпретатора](https://python-all.ru/3.15/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).

Изменено в версии 3.8: Функция обновлена для согласованности с [`PyEval_RestoreThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_RestoreThread), [`Py_END_ALLOW_THREADS()`](https://python-all.ru/3.15/c-api/threads.html#c.Py_END_ALLOW_THREADS) и [`PyGILState_Ensure()`](https://python-all.ru/3.15/c-api/threads.html#c.PyGILState_Ensure), и теперь завершает текущий поток, если вызвана во время завершения работы интерпретатора.

Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.

[`PyEval_RestoreThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_RestoreThread) – функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).

#### `void PyEval_ReleaseThread(PyThreadState *tstate)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Открепляет [прикреплённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state). Аргумент *tstate*, который не должен быть `NULL`, используется только для проверки того, что он представляет прикреплённое состояние потока – если это не так, сообщается о фатальной ошибке.

[`PyEval_SaveThread()`](https://python-all.ru/3.15/c-api/threads.html#c.PyEval_SaveThread) – функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).

# Асинхронные уведомления

Предоставляется механизм для асинхронных уведомлений основному потоку интерпретатора. Эти уведомления имеют форму указателя на функцию и аргумента в виде указателя void.

#### `int Py_AddPendingCall(int (*func)(void*), void *arg)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Планирует вызов функции из основного потока интерпретатора. В случае успеха возвращается `0`, и *func* помещается в очередь для вызова в основном потоке. В случае неудачи возвращается `-1` без установки какого-либо исключения.

При успешной постановке в очередь *func* будет *в конечном итоге* вызвана из основного потока интерпретатора с аргументом *arg*. Она будет вызвана асинхронно по отношению к нормально выполняющемуся коду Python, но при соблюдении обоих этих условий:

- на границе [байткода](https://python-all.ru/3.15/glossary.html#term-bytecode);
- при удержании основным потоком [присоединённого состояния потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) (поэтому *func* может использовать полный C API).

*func* должна возвращать `0` при успехе или `-1` при неудаче с установленным исключением. *func* не будет прервана для выполнения другого асинхронного уведомления рекурсивно, но всё же может быть прервана для переключения потоков, если [состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state) отсоединено.

Эта функция не требует [присоединённого состояния потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state). Однако для вызова этой функции в подынтерпретаторе вызывающий должен иметь присоединённое состояние потока. В противном случае функция *func* может быть запланирована для вызова из неправильного интерпретатора.

> **Предупреждение**
>
> Это низкоуровневая функция, полезная только в особых случаях. Нет гарантии, что *func* будет вызвана так быстро, насколько это возможно. Если основной поток занят выполнением системного вызова, *func* не будет вызвана до возврата из системного вызова. Эта функция в целом **не** подходит для вызова кода Python из произвольных потоков C. Вместо этого используйте [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThreadState_EnsureFromView).

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

Изменено в версии 3.9: Если эта функция вызывается в подынтерпретаторе, функция *func* теперь планируется для вызова из подынтерпретатора, а не из основного интерпретатора. Каждый подынтерпретатор теперь имеет свой собственный список запланированных вызовов.

Изменено в версии 3.12: Эта функция теперь всегда планирует выполнение *func* в основном интерпретаторе.

#### `int Py_MakePendingCalls(void)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Выполняет все отложенные вызовы. Обычно это выполняется автоматически интерпретатором.

Эта функция возвращает `0` при успехе и `-1` с установленным исключением при ошибке.

Если эта функция вызывается не в основном потоке главного интерпретатора, она ничего не делает и возвращает `0`. Вызывающий должен удерживать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

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

Изменено в версии 3.12: Эта функция выполняет отложенные вызовы только в основном интерпретаторе.

#### `int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Планирует асинхронное возбуждение исключения в потоке. Если в потоке уже было запланировано исключение, оно перезаписывается.

Аргумент *id* – это идентификатор потока целевого потока, как возвращается [`PyThread_get_thread_ident()`](https://python-all.ru/3.15/c-api/threads.html#c.PyThread_get_thread_ident). *exc* – это класс возбуждаемого исключения или `NULL` для очистки отложенного исключения (если есть).

Возвращает количество затронутых состояний потоков. Обычно это `1`, если *id* найден, даже если никаких изменений не было сделано (заданное *exc* уже было отложено, или *exc* равен `NULL`, но никакое исключение не отложено). Если идентификатор потока не найден, возвращает `0`. Это не возбуждает исключений.

Чтобы предотвратить наивное неправильное использование, необходимо написать собственное расширение C для вызова этой функции. Эта функция должна вызываться с [присоединённым состоянием потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state). Эта функция не [похищает](https://python-all.ru/3.15/glossary.html#term-steal) никакие ссылки на *exc*. Эта функция не обязательно прерывает системные вызовы, такие как [`sleep()`](https://python-all.ru/3.15/library/time.html#time.sleep).

Изменено в версии 3.7: Тип параметра *id* изменён с long на unsigned long.

# API потоков операционной системы

#### `PYTHREAD_INVALID_THREAD_ID`

Страж-значение для недопустимого идентификатора потока.

В настоящее время эквивалентно `(unsigned long)-1`.

#### `unsigned long PyThread_start_new_thread(void (*func)(void*), void *arg)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Запускает функцию *func* в новом потоке с аргументом *arg*. Полученный поток не предназначен для ожидания завершения.

*func* не должна быть `NULL`, но *arg* может быть `NULL`.

При успехе эта функция возвращает идентификатор нового потока; при неудаче возвращает [`PYTHREAD_INVALID_THREAD_ID`](https://python-all.ru/3.15/c-api/threads.html#c.PYTHREAD_INVALID_THREAD_ID).

Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

#### `unsigned long PyThread_get_thread_ident(void)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Возвращает идентификатор текущего потока, который никогда не будет равен нулю.

Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

> **См. также**
>
> [`threading.get_ident()`](https://python-all.ru/3.15/library/threading.html#threading.get_ident) и [`threading.Thread.ident`](https://python-all.ru/3.15/library/threading.html#threading.Thread.ident) предоставляют этот идентификатор в Python.

#### `PyObject *PyThread_GetInfo(void)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) начиная с версии 3.3.*

Получает общую информацию о текущем потоке в виде объекта [структурной последовательности](https://python-all.ru/3.15/c-api/tuple.html#struct-sequence-objects). Эта информация доступна как [`sys.thread_info`](https://python-all.ru/3.15/library/sys.html#sys.thread_info) в Python.

В случае успеха возвращается новая [сильная ссылка](https://python-all.ru/3.15/glossary.html#term-strong-reference) на информацию о потоке; в случае неудачи возвращается `NULL` с установленным исключением.

Вызывающий код должен удерживать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

#### `PY_HAVE_THREAD_NATIVE_ID`

Этот макрос определён, когда система поддерживает нативные идентификаторы потоков.

#### `unsigned long PyThread_get_thread_native_id(void)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable) на платформах с нативными идентификаторами потоков.*

Возвращает нативный идентификатор текущего потока, назначенный ядром операционной системы; это значение никогда не бывает меньше нуля.

Эта функция доступна, только если определён [`PY_HAVE_THREAD_NATIVE_ID`](https://python-all.ru/3.15/c-api/threads.html#c.PY_HAVE_THREAD_NATIVE_ID).

Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

> **См. также**
>
> [`threading.get_native_id()`](https://python-all.ru/3.15/library/threading.html#threading.get_native_id)

#### `void PyThread_exit_thread(void)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Завершает текущий поток. Эта функция обычно считается небезопасной, и её следует избегать. Она сохранена исключительно для обратной совместимости.

Эту функцию безопасно вызывать, только если все функции в полном стеке вызовов написаны так, чтобы допускать это безопасно.

> **Предупреждение**
>
> Если текущая система использует потоки POSIX (также известные как «pthreads»), эта функция вызывает *[pthread\_exit(3)](https://python-all.ru/3.15/c-api/threads.html)*, которая пытается развернуть стек и вызвать деструкторы C++ в некоторых реализациях libc. Однако, если достигается функция `noexcept`, это может завершить процесс. Другие системы, такие как macOS, выполняют развёртывание.
>
> В Windows эта функция вызывает `_endthreadex()`, которая уничтожает поток без вызова деструкторов C++.
>
> В любом случае существует риск повреждения стека потока.

Устарело с версии 3.14.

#### `void PyThread_init_thread(void)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Инициализирует API `PyThread*`. Python выполняет эту функцию автоматически, поэтому нет особой необходимости вызывать её из расширяющего модуля.

#### `int PyThread_set_stacksize(size_t size)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

Устанавливает размер стека текущего потока в *size* байт.

Эта функция возвращает `0` при успехе, `-1`, если *size* некорректен, или `-2`, если система не поддерживает изменение размера стека. Эта функция не устанавливает исключения.

Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).

#### `size_t PyThread_get_stacksize(void)`

*Часть [Stable ABI](https://python-all.ru/3.15/c-api/stable.html#stable).*

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

Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3.15/glossary.html#term-attached-thread-state).
