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

---

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

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

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

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

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

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

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

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

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

Если всё же потребуется создать состояние потока, вызовите [`PyThreadState_New()`](https://python-all.ru/3.14/c-api/threads.html#c.PyThreadState_New), затем [`PyThreadState_Swap()`](https://python-all.ru/3.14/c-api/threads.html#c.PyThreadState_Swap), или воспользуйтесь опасной функцией [`PyGILState_Ensure()`](https://python-all.ru/3.14/c-api/threads.html#c.PyGILState_Ensure).

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

Большая часть кода расширения, работающего с [состоянием потока](https://python-all.ru/3.14/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.14/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) открывает новый блок и объявляет скрытую локальную переменную; макрос [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.14/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.14/c-api/threads.html#c.PyEval_SaveThread), и результат сохраняется в локальной переменной.

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

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

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

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

### API

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

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

#### `Py_BEGIN_ALLOW_THREADS`

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

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

#### `Py_END_ALLOW_THREADS`

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

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

#### `Py_BLOCK_THREADS`

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

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

#### `Py_UNBLOCK_THREADS`

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

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

## Потоки, созданные не из Python

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

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

Самый надёжный способ – использовать [`PyThreadState_New()`](https://python-all.ru/3.14/c-api/threads.html#c.PyThreadState_New), а затем [`PyThreadState_Swap()`](https://python-all.ru/3.14/c-api/threads.html#c.PyThreadState_Swap).

> **Примечание**
>
> `PyThreadState_New` требует аргумента, указывающего на нужный интерпретатор; такой указатель можно получить вызовом [`PyInterpreterState_Get()`](https://python-all.ru/3.14/c-api/subinterpreters.html#c.PyInterpreterState_Get) из кода, в котором был создан поток.

Например:

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

/* Создаёт новое состояние потока для интерпретатора. Оно не начинается как
   присоединённым. */
PyThreadState *tstate = PyThreadState_New(interp);

/* Присоединить состояние потока, что приведёт к захвату GIL. */
PyThreadState_Swap(tstate);

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

/* Уничтожить состояние потока. После этой точки API Python не допускается. */
PyThreadState_Clear(tstate);
PyThreadState_DeleteCurrent();
```

> **Предупреждение**
>
> Если интерпретатор завершил работу до вызова `PyThreadState_Swap`, то `interp` окажется висячим указателем!

## Устаревший API

Ещё один распространённый способ вызова кода Python из потока, созданного не в Python, – использовать [`PyGILState_Ensure()`](https://python-all.ru/3.14/c-api/threads.html#c.PyGILState_Ensure), а затем вызвать [`PyGILState_Release()`](https://python-all.ru/3.14/c-api/threads.html#c.PyGILState_Release).

Эти функции плохо работают, когда в процессе Python существует несколько интерпретаторов. Если ни один интерпретатор Python ещё не использовался в текущем потоке (что характерно для потоков, созданных вне Python), `PyGILState_Ensure` создаст и присоединит состояние потока для «главного» интерпретатора (первого интерпретатора в процессе Python).

Кроме того, эти функции имеют проблемы с потоко-безопасностью при завершении интерпретатора. Использование `PyGILState_Ensure` во время завершения, скорее всего, приведёт к аварийному завершению процесса.

Использование этих функций выглядит так:

```c
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

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

/* Освободить поток. После этой точки API Python не допускается. */
PyGILState_Release(gstate);
```

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

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

Тот факт, что остаётся только «текущий» поток, означает, что любые блокировки, удерживаемые другими потоками, никогда не будут освобождены. Python решает эту проблему для [`os.fork()`](https://python-all.ru/3.14/library/os.html#os.fork), захватывая блокировки, которые он использует внутренне, перед fork и освобождая их после. Кроме того, он сбрасывает все [объекты блокировки](https://python-all.ru/3.14/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.14/c-api/sys.html#c.PyOS_AfterFork_Child) пытается сбросить необходимые блокировки, но не всегда может это сделать.

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

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

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

#### `type PyThreadState`

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

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

#### `PyInterpreterState *interp`

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

#### `void PyEval_InitThreads()`

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

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

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

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

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

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

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

#### `PyThreadState *PyEval_SaveThread()`

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

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

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

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

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

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

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

#### `PyThreadState *PyThreadState_Get()`

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

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

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

#### `PyThreadState *PyThreadState_GetUnchecked()`

Аналогично [`PyThreadState_Get()`](https://python-all.ru/3.14/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.14/c-api/stable.html#stable).*

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

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

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

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

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

Следующие функции используют локальное хранилище потока и несовместимы с подынтерпретаторами:

#### `type PyGILState_STATE`

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

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

#### `enumerator PyGILState_LOCKED`

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

#### `enumerator PyGILState_UNLOCKED`

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

#### `PyGILState_STATE PyGILState_Ensure()`

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

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

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

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

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

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

#### `void PyGILState_Release(PyGILState_STATE)`

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

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

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

#### `PyThreadState *PyGILState_GetThisThreadState()`

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

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

> **Примечание**
>
> Эта функция может вернуть не-`NULL`, даже если [состояние потока](https://python-all.ru/3.14/glossary.html#term-thread-state) отсоединено. Для большинства случаев предпочтительнее использовать [`PyThreadState_Get()`](https://python-all.ru/3.14/c-api/threads.html#c.PyThreadState_Get) или [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.14/c-api/threads.html#c.PyThreadState_GetUnchecked).

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

#### `int PyGILState_Check()`

Возвращает `1`, если текущий поток удерживает [GIL](https://python-all.ru/3.14/glossary.html#term-GIL), и `0` в противном случае. Эту функцию можно вызывать из любого потока в любое время. Только если её [состояние потока](https://python-all.ru/3.14/glossary.html#term-attached-thread-state) было инициализировано через [`PyGILState_Ensure()`](https://python-all.ru/3.14/c-api/threads.html#c.PyGILState_Ensure), она вернёт `1`. В основном это вспомогательная/диагностическая функция. Она может быть полезна, например, в контекстах колбэков или функций выделения памяти, когда знание того, что GIL заблокирован, может позволить вызывающему выполнять чувствительные действия или иначе вести себя по-другому.

> **Примечание**
>
> Если текущий процесс Python когда-либо создавал подынтерпретатор, эта функция будет *всегда* возвращать `1`. Для большинства случаев предпочтительнее использовать [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.14/c-api/threads.html#c.PyThreadState_GetUnchecked).

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

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

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

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

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

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

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

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

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

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

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

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

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

#### `void PyThreadState_DeleteCurrent(void)`

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

См. также функции [`PyEval_SetTrace()`](https://python-all.ru/3.14/c-api/profiling.html#c.PyEval_SetTrace) и [`PyEval_SetProfile()`](https://python-all.ru/3.14/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.14/c-api/stable.html#unstable-c-api). Оно может меняться без предупреждения в минорных версиях.*

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

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

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

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

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

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

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

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

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

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

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

#### `PyObject *PyThreadState_GetDict()`

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

#### `int Py_MakePendingCalls(void)`

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

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

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

Если эта функция вызывается не в основном потоке главного интерпретатора, она ничего не делает и возвращает `0`. Вызывающий должен удерживать [присоединённое состояние потока](https://python-all.ru/3.14/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.14/c-api/stable.html#stable).*

Асинхронно возбуждает исключение в потоке. Аргумент *id* – это идентификатор целевого потока; *exc* – объект исключения, которое нужно возбудить. Эта функция не [крадёт](https://python-all.ru/3.14/glossary.html#term-steal) ссылки на *exc*. Чтобы предотвратить наивное злоупотребление, необходимо написать собственное C-расширение для её вызова. Должна вызываться с [прикреплённым состоянием потока](https://python-all.ru/3.14/glossary.html#term-attached-thread-state). Возвращает количество изменённых состояний потока; обычно это единица, но будет нулём, если идентификатор потока не найден. Если *exc* равно `NULL`, ожидающее исключение (если есть) для потока очищается. Эта функция не возбуждает исключений.

Изменено в версии 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.14/c-api/stable.html#stable).*

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

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

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

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

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

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

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

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

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

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

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

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

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

Вызывающий код должен удерживать [присоединённое состояние потока](https://python-all.ru/3.14/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.14/c-api/stable.html#stable) на платформах с нативными идентификаторами потоков.*

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

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

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

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

#### `void PyThread_exit_thread(void)`

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

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

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

> **Предупреждение**
>
> Если текущая система использует потоки POSIX (также известные как «pthreads»), эта функция вызывает *[pthread\_exit(3)](https://python-all.ru/3.14/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.14/c-api/stable.html#stable).*

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

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

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

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

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

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

#### `size_t PyThread_get_stacksize(void)`

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

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

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