threads.md
1> **Источник:** https://python-all.ru/3.16/c-api/threads.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Состояния потоков и глобальная блокировка интерпретатора89За исключением [сборки со свободной многопоточностью](https://python-all.ru/3.16/glossary.html#term-free-threaded-build) [CPython](https://python-all.ru/3.16/glossary.html#term-CPython), интерпретатор Python в целом не является потокобезопасным. Для поддержки многопоточных программ на Python существует глобальная блокировка, называемая [глобальной блокировкой интерпретатора](https://python-all.ru/3.16/glossary.html#term-global-interpreter-lock), или [GIL](https://python-all.ru/3.16/glossary.html#term-GIL), которую поток должен захватить перед доступом к объектам Python. Без этой блокировки даже простейшие операции могут вызвать проблемы в многопоточной программе: например, если два потока одновременно увеличивают счётчик ссылок одного и того же объекта, счётчик может увеличиться только один раз вместо двух.1011Таким образом, только поток, удерживающий GIL, может работать с объектами Python или вызывать C API Python.1213Для эмуляции параллелизма интерпретатор регулярно пытается переключать потоки между инструкциями байт-кода (см. [`sys.setswitchinterval()`](https://python-all.ru/3.16/library/sys.html#sys.setswitchinterval)). Поэтому блокировки также необходимы для потокобезопасности в коде на чистом Python.1415Кроме того, глобальная блокировка интерпретатора освобождается вокруг блокирующих операций ввода-вывода, таких как чтение или запись в файл. В C API это делается с помощью [отсоединения состояния потока](https://python-all.ru/3.16/c-api/threads.html#detaching-thread-state).1617Интерпретатор Python хранит некоторую локальную для потока информацию внутри структуры данных, называемой [`PyThreadState`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState), известной как [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state). Каждый поток имеет указатель, локальный для потока, на `PyThreadState`; состояние потока, на которое ссылается этот указатель, считается [присоединённым](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).1819Поток может иметь только одно [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) в каждый момент времени. Присоединённое состояние потока обычно аналогично удержанию GIL, за исключением сборок со свободной многопоточностью. В сборках с включённым GIL присоединение состояния потока будет блокироваться до тех пор, пока не будет получен GIL. Однако даже в сборках с отключённым GIL всё равно требуется иметь присоединённое состояние потока, поскольку интерпретатору необходимо отслеживать, какие потоки могут обращаться к объектам Python.2021> **Примечание**22>23> Даже в сборке со свободной многопоточностью присоединение состояния потока может блокироваться, так как GIL может быть повторно включён, или потоки могут быть временно приостановлены (например, во время сборки мусора).2425Обычно при использовании C API Python всегда есть присоединённое состояние потока, в том числе при встраивании и реализации методов, так что необходимость самостоятельно настраивать состояние потока возникает редко. Только в некоторых особых случаях, например в блоке [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) или в новом потоке, поток не будет иметь присоединённого состояния потока. Если есть сомнения, проверьте, возвращает ли [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_GetUnchecked) `NULL`.2627Если всё же необходимо создать состояние потока, рекомендуется использовать [`PyThreadState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_EnsureFromView), которые управляют состоянием потока.2829## Отсоединение состояния потока из кода расширения3031Большая часть кода расширения, работающего с [состоянием потока](https://python-all.ru/3.16/glossary.html#term-thread-state), имеет следующую простую структуру:3233```c34Save the thread state in a local variable.35... Do some blocking I/O operation ...36Restore the thread state from the local variable.37```3839Это настолько распространено, что существует пара макросов для упрощения:4041```c42Py_BEGIN_ALLOW_THREADS43... Do some blocking I/O operation ...44Py_END_ALLOW_THREADS45```4647Макрос [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) открывает новый блок и объявляет скрытую локальную переменную; макрос [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_END_ALLOW_THREADS) закрывает блок.4849Приведённый выше блок раскрывается в следующий код:5051```c52PyThreadState *_save;5354_save = PyEval_SaveThread();55... Do some blocking I/O operation ...56PyEval_RestoreThread(_save);57```5859Вот как работают эти функции:6061Присоединённое состояние потока подразумевает, что GIL удерживается для интерпретатора. Чтобы отсоединить его, вызывается [`PyEval_SaveThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_SaveThread), и результат сохраняется в локальной переменной.6263Отсоединяя состояние потока, GIL освобождается, что позволяет другим потокам присоединиться к интерпретатору и выполняться, пока текущий поток выполняет блокирующий ввод-вывод. Когда операция ввода-вывода завершается, старое состояние потока повторно присоединяется вызовом [`PyEval_RestoreThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_RestoreThread), который будет ожидать, пока не удастся захватить GIL.6465> **Примечание**66>67> Выполнение блокирующего ввода-вывода – самый распространённый случай применения отсоединения состояния потока, но его также полезно вызывать в длительном нативном коде, которому не нужен доступ к объектам Python или C API Python. Например, стандартные модули [`zlib`](https://python-all.ru/3.16/library/zlib.html#module-zlib) и [`hashlib`](https://python-all.ru/3.16/library/hashlib.html#module-hashlib) отсоединяют [состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) при сжатии или хешировании данных.6869В [сборке со свободной многопоточностью](https://python-all.ru/3.16/glossary.html#term-free-threaded-build) [GIL](https://python-all.ru/3.16/glossary.html#term-GIL) обычно не рассматривается, но **отсоединение состояния потока всё равно требуется**, потому что интерпретатору периодически нужно блокировать все потоки для получения согласованного представления объектов Python без риска состояний гонки. Например, CPython в настоящее время приостанавливает все потоки на короткое время во время работы сборщика мусора.7071> **Предупреждение**72>73> Отсоединение состояния потока может привести к неожиданному поведению во время завершения работы интерпретатора. См. раздел [Предостережения относительно завершения работы интерпретатора](https://python-all.ru/3.16/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization) для получения более подробной информации.7475### API7677Следующие макросы обычно используются без точки с запятой в конце; примеры использования можно найти в дистрибутиве исходного кода Python.7879> **Примечание**80>81> Эти макросы всё ещё необходимы в [сборке со свободной многопоточностью](https://python-all.ru/3.16/glossary.html#term-free-threaded-build) для предотвращения взаимоблокировок.8283#### `Py_BEGIN_ALLOW_THREADS`8485*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*8687Этот макрос раскрывается в `{ PyThreadState *_save; _save = PyEval_SaveThread();`. Обратите внимание, что он содержит открывающую фигурную скобку; она должна быть сопоставлена с последующим макросом [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_END_ALLOW_THREADS). См. выше дополнительное обсуждение этого макроса.8889#### `Py_END_ALLOW_THREADS`9091*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*9293Этот макрос раскрывается в `PyEval_RestoreThread(_save); }`. Обратите внимание, что он содержит закрывающую фигурную скобку; она должна быть сопоставлена с предыдущим макросом [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS). См. выше дополнительное обсуждение этого макроса.9495#### `Py_BLOCK_THREADS`9697*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*9899Этот макрос разворачивается в `PyEval_RestoreThread(_save);`: он эквивалентен [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_END_ALLOW_THREADS) без закрывающей фигурной скобки.100101#### `Py_UNBLOCK_THREADS`102103*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*104105Этот макрос разворачивается в `_save = PyEval_SaveThread();`: он эквивалентен [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) без открывающей фигурной скобки и объявления переменной.106107## Использование C API из внешних потоков108109Когда потоки создаются с помощью специальных Python API (таких как модуль [`threading`](https://python-all.ru/3.16/library/threading.html#module-threading)), состояние потока автоматически связывается с ними. Однако, когда поток создается из нативного кода (например, сторонней библиотекой с собственным управлением потоками), он не имеет прикрепленного состояния потока.110111Если нужно вызвать код Python из этих потоков (часто это будет частью колбэк-API, предоставляемого вышеупомянутой сторонней библиотекой), необходимо сначала зарегистрировать эти потоки в интерпретаторе, создав новое состояние потока и прикрепив его.112113Самый простой способ сделать это – через [`PyThreadState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_EnsureFromView).114115> **Примечание**116>117> Эти функции требуют аргумент, указывающий на нужный интерпретатор; такой указатель можно получить вызовом [`PyInterpreterGuard_FromCurrent()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.PyInterpreterGuard_FromCurrent) (для `PyThreadState_Ensure`) или [`PyInterpreterView_FromCurrent()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.PyInterpreterView_FromCurrent) (для `PyThreadState_EnsureFromView`) из функции, создающей поток. Если указатель недоступен (например, когда заданная нативная библиотека потоков не предоставляет аргумент data), можно использовать [`PyInterpreterView_FromMain()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.PyInterpreterView_FromMain) для получения представления главного интерпретатора, но учтите, что это сделает код несовместимым с субинтерпретаторами.118119Например:120121```c122// Возвращаемое значение PyInterpreterGuard_FromCurrent() из123// функции, создавшей этот поток.124PyInterpreterGuard *guard = thread_data->guard;125126// Создаёт новое состояние потока для интерпретатора.127PyThreadStateToken *token = PyThreadState_Ensure(guard);128if (token == NULL) {129 PyInterpreterGuard_Close(guard);130 return;131}132133// Имеется корректное состояние потока – выполните здесь действия Python.134result = CallSomeFunction();135// Вычислить результат или обработать исключения.136137// Освободить состояние потока. Вызовы C API не допускаются после этой138// точки.139PyThreadState_Release(token);140PyInterpreterGuard_Close(guard);141```142143Имейте в виду, что вызов `PyThreadState_Ensure` не всегда создает новое состояние потока, а вызов `PyThreadState_Release` не всегда его отсоединяет. Эти функции могут повторно использовать существующее прикрепленное состояние потока или повторно прикрепить состояние потока, которое ранее было прикреплено для текущего потока.144145> **См. также**146>147> [**PEP 788**](https://python-all.ru/3.16/c-api/threads.html)148149### Повторное использование состояния потока при многократных вызовах150151Создание и уничтожение [`PyThreadState`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState) небесплатно и стоит дороже на [сборке со свободными потоками](https://python-all.ru/3.16/glossary.html#term-free-threaded-build). Внешний поток, много раз вызывающий интерпретатор – например, рабочий поток в нативном пуле потоков – должен избегать создания нового состояния потока при каждом входе и уничтожения его при каждом выходе. Вместо этого следует настроить одно состояние потока при запуске потока (или лениво при его первом вызове в Python), прикреплять и отсоединять его вокруг каждого вызова и один раз уничтожить, когда поток завершается.152153Управляйте состоянием потока явно с помощью [`PyThreadState_New()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_New), прикрепляя и отсоединяя его с помощью [`PyEval_RestoreThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_RestoreThread) и [`PyEval_SaveThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_SaveThread). Это происходит в три отдельных этапа, в разные моменты жизни потока.154155Когда поток запускается, создайте одно состояние потока для него. `interp` – это целевой интерпретатор, захваченный кодом, создавшим этот поток, пока у него было прикрепленное состояние потока (например, через [`PyInterpreterState_Get()`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterState_Get)):156157```c158PyThreadState *tstate = PyThreadState_New(interp);159```160161Затем при каждом вызове Python – который может происходить много раз в течение жизни потока – прикрепите состояние потока, выполните вызовы C API Python, требующие его, и снова отсоедините, чтобы поток не удерживал GIL, когда занимается не-Python работой:162163```c164PyEval_RestoreThread(tstate);165result = CallSomeFunction(); /* Здесь размещаются ваши вызовы Python C API. */166PyEval_SaveThread();167```168169Когда поток завершит вызовы в Python, уничтожьте состояние потока один раз:170171```c172PyEval_RestoreThread(tstate);173PyThreadState_Clear(tstate);174PyThreadState_DeleteCurrent();175```176177Универсальные точки входа для вызова из внешнего потока – [`PyThreadState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Ensure) и старая [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure) – *не* гарантируют постоянное состояние потока: время жизни их состояния потока намеренно определено реализацией, поэтому пара acquire/release может создавать и уничтожать состояние потока каждый раз. Используйте [`PyThreadState_New()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_New), как показано здесь, когда необходимо повторно использовать одно состояние потока при вызовах.178179Код, создавший внешний поток, должен организовать выполнение последовательности завершения до выхода потока и до вызова [`Py_FinalizeEx()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_FinalizeEx). Если сначала начнется финализация интерпретатора, вызов shutdown [`PyEval_RestoreThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_RestoreThread) зависнет, а не вернется (см. [Предостережения относительно финализации интерпретатора](https://python-all.ru/3.16/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization)). Если поток завершится без выполнения последовательности завершения, состояние потока будет утечено на оставшееся время процесса.180181### Прикрепление/отсоединение состояний потоков182183#### `PyThreadStateToken *PyThreadState_Ensure(PyInterpreterGuard *guard)`184185*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.15.*186187Гарантирует, что поток имеет прикрепленное состояние потока для интерпретатора, защищенного *guard*, и поэтому может безопасно вызывать этот интерпретатор.188189Вызов этой функции допустим, если поток уже имеет прикрепленное состояние потока, при условии, что последует вызов [`PyThreadState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Release), соответствующий этому (то есть разрешены “вложенные” вызовы этой функции).190191Эффект функции (если он есть) будет отменен соответствующим вызовом [`PyThreadState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Release).192193В случае ошибки эта функция возвращает `NULL` *без* установленного исключения. Не вызывайте `PyThreadState_Release()` в этом случае.194195При успехе эта функция возвращает значение указателя, которое должно быть передано в соответствующий вызов `PyThreadState_Release()`.196197Условия, при которых эта функция создает новое [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state), считаются нестабильными и зависящими от реализации. Если необходимо управлять точным временем жизни состояния потока, рассмотрите использование [`PyThreadState_New()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_New). Однако не избегайте этой функции только на том основании, что время жизни состояния потока может быть несовместимым между версиями; изменения в этой функции будут проводиться с осторожностью и обратно совместимым образом. В частности, сохранение локальных переменных потока и аналогичного состояния будет сохранено между версиями Python.198199**Деталь реализации CPython:** Точное поведение относительно того, создает ли эта функция новое состояние потока, описано ниже, но имейте в виду, что это может измениться в будущем.200201Сначала функция проверяет, присутствует ли прикрепленное состояние потока. Если да, функция проверяет, совпадает ли интерпретатор этого состояния потока с интерпретатором, защищенным *guard*. Если это так, функция просто помечает состояние потока как используемое вызовом `PyThreadState_Ensure` и возвращается.202203Если прикрепленного состояния потока нет, функция проверяет, использовалось ли какое-либо состояние потока текущим потоком ОС. (Это возвращается [`PyGILState_GetThisThreadState()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_GetThisThreadState).) Если да, функция проверяет, совпадает ли интерпретатор этого состояния потока с *guard*. Если совпадает, оно повторно прикрепляется и помечается как используемое.204205В противном случае, если оба вышеуказанных случая не сработали, создается новое состояние потока для *guard*. Затем оно прикрепляется и помечается как принадлежащее `PyThreadState_Ensure`.206207Добавлено в версии 3.15.208209#### `PyThreadStateToken *PyThreadState_EnsureFromView(PyInterpreterView *view)`210211*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.15.*212213Получить присоединённое состояние потока для интерпретатора, на который ссылается *view*.214215Поведение и возвращаемое значение такие же, как для [`PyThreadState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Ensure); дополнительно, если функция завершается успешно, интерпретатор, на который ссылается *view*, будет неявно защищён. Защита будет снята при соответствующем вызове [`PyThreadState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Release).216217Добавлено в версии 3.15.218219#### `void PyThreadState_Release(PyThreadStateToken *token)`220221*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.15.*222223Отменить вызов [`PyThreadState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_EnsureFromView).224225Эта функция должна вызываться ровно один раз для каждого успешного вызова *Ensure*, при этом *token* должен быть установлен в возвращаемое значение этого вызова.226227Состояние, которое было присоединено до соответствующего вызова *Ensure* (если таковое имелось), будет присоединено снова, когда [`PyThreadState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Release) вернёт управление.228229Точное поведение того, удаляет ли эта функция состояние потока, считается нестабильным и зависит от реализации.230231**Особенность реализации CPython:** В настоящее время эта функция уменьшает внутренний счётчик присоединённого состояния потока. Если этот счётчик когда-либо опускается ниже нуля, функция вызывает фатальную ошибку (через [`Py_FatalError()`](https://python-all.ru/3.16/c-api/sys.html#c.Py_FatalError)).232233Если присоединённое состояние потока принадлежит `PyThreadState_Ensure`, то оно будет освобождено и удалено, когда внутренний счётчик достигнет нуля. В противном случае при достижении счётчиком нуля ничего не происходит.234235Добавлено в версии 3.15.236237#### `type PyThreadStateToken`238239*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) (как непрозрачная структура) начиная с версии 3.15.*240241Непрозрачный токен, полученный из вызова [`PyThreadState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Ensure) и переданный в соответствующий вызов [`PyThreadState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Release).242243## API состояния GIL244245Следующие API в целом несовместимы с подынтерпретаторами и приведут к зависанию процесса во время финализации интерпретатора (см. [Предостережения относительно финализации интерпретатора](https://python-all.ru/3.16/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization)). Поэтому эти API были [мягко устарели](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) в Python 3.15 в пользу [новых API](https://python-all.ru/3.16/c-api/threads.html#c-api-foreign-threads).246247#### `type PyGILState_STATE`248249*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*250251Тип значения, возвращаемого [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure) и передаваемого в [`PyGILState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Release).252253#### `enumerator PyGILState_LOCKED`254255GIL уже был захвачен, когда была вызвана [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure).256257#### `enumerator PyGILState_UNLOCKED`258259GIL не был захвачен, когда была вызвана [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure).260261#### `PyGILState_STATE PyGILState_Ensure()`262263*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*264265Гарантирует, что текущий поток готов вызывать Python C API независимо от текущего состояния Python или [присоединённого состояния потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Эта функция может вызываться потоком сколько угодно раз, при условии, что каждый вызов сопровождается вызовом [`PyGILState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Release). В целом, другие потоковые API могут использоваться между вызовами [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure) и `PyGILState_Release()`, если состояние потока восстанавливается в предыдущее состояние до вызова Release(). Например, обычное использование макросов [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) и [`Py_END_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_END_ALLOW_THREADS) допустимо.266267Возвращаемое значение – это непрозрачный «дескриптор» [присоединённого состояния потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) на момент вызова [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure), и его необходимо передать в [`PyGILState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Release), чтобы гарантировать, что Python останется в том же состоянии. Несмотря на то, что рекурсивные вызовы разрешены, эти дескрипторы *нельзя* совместно использовать – каждый уникальный вызов `PyGILState_Ensure()` должен сохранить дескриптор для своего вызова `PyGILState_Release()`.268269После возврата функции будет существовать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state), и поток сможет вызывать произвольный код Python.270271У этой функции нет способа вернуть ошибку. Поэтому ошибки либо фатальны (то есть они отправляют `SIGABRT` и аварийно завершают процесс; см. [`Py_FatalError()`](https://python-all.ru/3.16/c-api/sys.html#c.Py_FatalError)), либо поток будет заблокирован бессрочно (например, во время финализации интерпретатора).272273> **Предупреждение**274>275> Вызов этой функции во время финализации интерпретатора приведёт к бесконечному зависанию потока, что может вызвать взаимоблокировки. [Предостережения относительно финализации интерпретатора](https://python-all.ru/3.16/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization) для подробностей.276>277> Кроме того, эта функция в целом не работает с подынтерпретаторами при использовании из внешних потоков, так как у неё нет способа узнать, какой интерпретатор создал поток (и поэтому она неявно выбирает главный интерпретатор).278279Изменено в версии 3.14: При вызове во время финализации интерпретатора теперь зависает текущий поток, а не завершает его.280281[Мягко устарело](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) начиная с версии 3.15: Используйте [`PyThreadState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Ensure) или [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_EnsureFromView) вместо него.282283#### `void PyGILState_Release(PyGILState_STATE)`284285*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*286287Освобождает все ранее приобретённые ресурсы. После этого вызова состояние Python будет таким же, как до соответствующего вызова [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure) (но обычно это состояние неизвестно вызывающей стороне, поэтому и используется API состояния GIL).288289Каждый вызов [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure) должен сопровождаться вызовом [`PyGILState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Release) в том же потоке.290291[Мягко устарело](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) начиная с версии 3.15: Используйте [`PyThreadState_Release()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Release) вместо него.292293#### `PyThreadState *PyGILState_GetThisThreadState()`294295*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*296297Получить [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state), которое последним было [присоединено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) для этого потока. (Если последнее состояние потока было удалено, эта функция возвращает `NULL`.)298299Если у вызывающего есть присоединённое состояние потока, оно возвращается.300301Другими словами, эта функция возвращает состояние потока, которое будет использовано [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure). Если она возвращает `NULL`, то `PyGILState_Ensure` создаёт новое состояние потока.302303Эта функция не может завершиться с ошибкой.304305[Мягко устарело](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) начиная с версии 3.15: Вместо этого используйте [`PyThreadState_Get()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Get) или [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_GetUnchecked).306307#### `int PyGILState_Check()`308309Возвращает `1`, если текущий поток имеет [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state), которое совпадает с состоянием потока, возвращаемым [`PyGILState_GetThisThreadState()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_GetThisThreadState). Если у вызывающего нет присоединённого состояния потока или оно не совпадает, то возвращается `0`.310311Если текущий процесс Python когда-либо создавал суб-интерпретатор, эта функция будет *всегда* возвращать `1`.312313Это в основном вспомогательная/диагностическая функция.314315Добавлено в версии 3.4.316317[Мягко устарело](https://python-all.ru/3.16/glossary.html#term-soft-deprecated) начиная с версии 3.15: Вместо этого используйте `PyThreadState_GetUnchecked() != NULL`.318319## Предостережения относительно fork()320321Ещё одна важная особенность потоков – их поведение при вызове C `fork()`. На большинстве систем с `fork()` после fork процесса остаётся только тот поток, который вызвал fork. Это оказывает конкретное влияние как на обработку блокировок, так и на всё сохранённое состояние в среде выполнения CPython.322323Тот факт, что остаётся только «текущий» поток, означает, что любые блокировки, удерживаемые другими потоками, никогда не будут освобождены. Python решает эту проблему для [`os.fork()`](https://python-all.ru/3.16/library/os.html#os.fork), захватывая блокировки, которые он использует внутренне, перед fork и освобождая их после. Кроме того, он сбрасывает все [объекты блокировки](https://python-all.ru/3.16/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.16/c-api/sys.html#c.PyOS_AfterFork_Child) пытается сбросить необходимые блокировки, но не всегда может это сделать.324325Тот факт, что все остальные потоки исчезают, также означает, что состояние среды выполнения CPython должно быть правильно очищено, что и делает [`os.fork()`](https://python-all.ru/3.16/library/os.html#os.fork). Это означает завершение всех остальных объектов [`PyThreadState`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState), принадлежащих текущему интерпретатору, и всех остальных объектов [`PyInterpreterState`](https://python-all.ru/3.16/c-api/subinterpreters.html#c.PyInterpreterState). Из-за этого и особой природы [«главного» интерпретатора](https://python-all.ru/3.16/c-api/subinterpreters.html#sub-interpreter-support), `fork()` следует вызывать только в «главном» потоке этого интерпретатора, где изначально была инициализирована глобальная среда выполнения CPython. Единственное исключение – если `exec()` будет вызван сразу после.326327## API высокого уровня328329Это наиболее часто используемые типы и функции при написании многопоточных расширений на C.330331#### `type PyThreadState`332333*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) (как непрозрачная структура).*334335Эта структура данных представляет состояние одного потока. Единственный открытый элемент данных:336337#### `PyInterpreterState *interp`338339Состояние интерпретатора этого потока.340341#### `void PyEval_InitThreads()`342343*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*344345Устаревшая функция, которая ничего не делает.346347В Python 3.6 и старше эта функция создавала GIL, если его не существовало.348349Изменено в версии 3.9: Теперь функция ничего не делает.350351Изменено в версии 3.7: Теперь эта функция вызывается [`Py_Initialize()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_Initialize), так что вам больше не нужно вызывать её самостоятельно.352353Изменено в версии 3.2: Эту функцию больше нельзя вызывать до [`Py_Initialize()`](https://python-all.ru/3.16/c-api/interp-lifecycle.html#c.Py_Initialize).354355Устарело с версии 3.9.356357#### `PyThreadState *PyEval_SaveThread()`358359*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*360361Отсоединить [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) и вернуть его. После возврата у потока не будет [состояния потока](https://python-all.ru/3.16/glossary.html#term-thread-state).362363#### `void PyEval_RestoreThread(PyThreadState *tstate)`364365*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*366367Установить [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) в *tstate*. Переданное [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state) **не должно** быть присоединённым, иначе произойдёт взаимоблокировка. *tstate* будет присоединён после возврата.368369> **Примечание**370>371> Вызов этой функции из потока во время завершения работы среды выполнения приведёт к зависанию потока до выхода из программы, даже если поток не был создан Python. Подробнее см. [Предостережения относительно завершения работы интерпретатора](https://python-all.ru/3.16/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).372373Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.374375#### `PyThreadState *PyThreadState_Get()`376377*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*378379Возвращает [прикреплённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Если у потока нет прикреплённого состояния потока (например, при нахождении внутри блока [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3.16/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS)), то возникает фатальная ошибка (поэтому вызывающему коду не нужно проверять `NULL`).380381См. также [`PyThreadState_GetUnchecked()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_GetUnchecked).382383#### `PyThreadState *PyThreadState_GetUnchecked()`384385Аналогично [`PyThreadState_Get()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Get), но не завершает процесс фатальной ошибкой, если значение равно NULL. Вызывающий код должен самостоятельно проверить, не является ли результат NULL.386387Добавлено в версии 3.13: В версиях Python с 3.5 по 3.12 эта функция была приватной и называлась `_PyThreadState_UncheckedGet()`.388389#### `PyThreadState *PyThreadState_Swap(PyThreadState *tstate)`390391*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*392393Устанавливает [прикреплённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) равным *tstate* и возвращает [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state), которое было прикреплено до вызова.394395Эту функцию можно безопасно вызывать без [прикреплённого состояния потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state); она просто вернёт `NULL`, указывая, что предыдущего состояния потока не было.396397> **См. также**398>399> [`PyEval_ReleaseThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_ReleaseThread)400401> **Примечание**402>403> Аналогично [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure), эта функция приведёт к зависанию потока, если среда выполнения завершает работу.404405## Низкоуровневые API406407#### `PyThreadState *PyThreadState_New(PyInterpreterState *interp)`408409*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*410411Создаёт новый объект состояния потока, принадлежащий указанному объекту интерпретатора. [Прикреплённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) не требуется.412413#### `void PyThreadState_Clear(PyThreadState *tstate)`414415*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*416417Сбрасывает всю информацию в объекте [состояния потока](https://python-all.ru/3.16/glossary.html#term-thread-state). *tstate* должно быть [прикреплено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).418419Изменено в версии 3.9: Теперь эта функция вызывает колбэк `PyThreadState.on_delete`. Ранее это происходило в [`PyThreadState_Delete()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Delete).420421Изменено в версии 3.13: Колбэк `PyThreadState.on_delete` удалён.422423#### `void PyThreadState_Delete(PyThreadState *tstate)`424425*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*426427Уничтожает объект [состояния потока](https://python-all.ru/3.16/glossary.html#term-thread-state). *tstate* не должно быть [прикреплено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) ни к какому потоку. *tstate* должно быть предварительно сброшено вызовом [`PyThreadState_Clear()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Clear).428429#### `void PyThreadState_DeleteCurrent(void)`430431Открепляет [прикреплённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) (которое должно быть предварительно сброшено вызовом [`PyThreadState_Clear()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_Clear)) и затем уничтожает его.432433После возврата никакое [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state) не будет [прикреплено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).434435#### `PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)`436437*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.10.*438439Возвращает текущий кадр состояния потока Python *tstate*.440441Возвращает [сильную ссылку](https://python-all.ru/3.16/glossary.html#term-strong-reference). Возвращает `NULL`, если в данный момент кадр не выполняется.442443См. также [`PyEval_GetFrame()`](https://python-all.ru/3.16/c-api/reflection.html#c.PyEval_GetFrame).444445*tstate* не должно быть `NULL` и должно быть [прикреплено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).446447Добавлено в версии 3.9.448449#### `uint64_t PyThreadState_GetID(PyThreadState *tstate)`450451*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.10.*452453Возвращает уникальный [идентификатор состояния потока](https://python-all.ru/3.16/glossary.html#term-thread-state) для состояния потока Python *tstate*.454455*tstate* не должно быть `NULL` и должно быть [прикреплено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).456457Добавлено в версии 3.9.458459#### `PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)`460461*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.10.*462463Возвращает интерпретатор состояния потока Python *tstate*.464465*tstate* не должен быть `NULL` и должен быть [прикреплён](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).466467Добавлено в версии 3.9.468469#### `void PyThreadState_EnterTracing(PyThreadState *tstate)`470471Приостанавливает трассировку и профилирование в состоянии потока Python *tstate*.472473Возобновляет их с помощью функции [`PyThreadState_LeaveTracing()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_LeaveTracing).474475Добавлено в версии 3.12.476477#### `void PyThreadState_LeaveTracing(PyThreadState *tstate)`478479Возобновляет трассировку и профилирование в состоянии потока Python *tstate*, приостановленные функцией [`PyThreadState_EnterTracing()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_EnterTracing).480481См. также функции [`PyEval_SetTrace()`](https://python-all.ru/3.16/c-api/profiling.html#c.PyEval_SetTrace) и [`PyEval_SetProfile()`](https://python-all.ru/3.16/c-api/profiling.html#c.PyEval_SetProfile).482483Добавлено в версии 3.12.484485#### `int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size)`486487> *Это [нестабильное API](https://python-all.ru/3.16/c-api/stable.html#unstable-c-api). Оно может меняться без предупреждения в минорных версиях.*488489Устанавливает начальный адрес защиты стека и размер защиты стека состояния потока Python.490491В случае успеха возвращает `0`. В случае неудачи устанавливает исключение и возвращает `-1`.492493CPython реализует [контроль рекурсии](https://python-all.ru/3.16/c-api/exceptions.html#recursion) для кода на C, вызывая [`RecursionError`](https://python-all.ru/3.16/library/exceptions.html#RecursionError), когда замечает, что стек выполнения машины близок к переполнению. См., например, функцию [`Py_EnterRecursiveCall()`](https://python-all.ru/3.16/c-api/exceptions.html#c.Py_EnterRecursiveCall). Для этого ему нужно знать расположение стека текущего потока, которое он обычно получает от операционной системы. При изменении стека, например, с помощью методов переключения контекста, таких как `boost::context` библиотеки Boost, необходимо вызвать [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3.16/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection), чтобы сообщить CPython об изменении.494495Необходимо вызвать [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3.16/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection) либо до, либо после изменения стека. Не следует вызывать другие функции Python C API между этим вызовом и изменением стека.496497Для отмены этой операции см. [`PyUnstable_ThreadState_ResetStackProtection()`](https://python-all.ru/3.16/c-api/threads.html#c.PyUnstable_ThreadState_ResetStackProtection).498499Добавлено в версии 3.15.500501#### `void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)`502503> *Это [нестабильное API](https://python-all.ru/3.16/c-api/stable.html#unstable-c-api). Оно может меняться без предупреждения в минорных версиях.*504505Сбрасывает начальный адрес защиты стека и размер защиты стека состояния потока Python в значения по умолчанию операционной системы.506507Пояснение см. в [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3.16/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection).508509Добавлено в версии 3.15.510511#### `PyObject *PyThreadState_GetDict()`512513*Возвращаемое значение: заимствованная ссылка.*514515*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*516517Возвращает словарь, в котором расширения могут хранить информацию о состоянии, специфичном для потока. Каждое расширение должно использовать уникальный ключ для хранения состояния в словаре. Допускается вызов этой функции, когда [состояние потока](https://python-all.ru/3.16/glossary.html#term-thread-state) не [прикреплено](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Если эта функция возвращает `NULL` и при этом не было возбуждено исключение, то вызывающий должен считать, что состояние потока не прикреплено.518519#### `void PyEval_AcquireThread(PyThreadState *tstate)`520521*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*522523[Прикрепляет](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) *tstate* к текущему потоку, который не должен быть `NULL` или уже прикреплён.524525Вызывающий поток не должен уже иметь [прикреплённого состояния потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).526527> **Примечание**528>529> Вызов этой функции из потока во время завершения работы среды выполнения приведёт к зависанию потока до выхода программы, даже если поток не был создан Python. Подробнее см. [Предостережения относительно завершения интерпретатора](https://python-all.ru/3.16/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).530531Изменено в версии 3.8: Функция обновлена для согласованности с [`PyEval_RestoreThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_RestoreThread), [`Py_END_ALLOW_THREADS()`](https://python-all.ru/3.16/c-api/threads.html#c.Py_END_ALLOW_THREADS) и [`PyGILState_Ensure()`](https://python-all.ru/3.16/c-api/threads.html#c.PyGILState_Ensure), и теперь завершает текущий поток, если вызвана во время завершения работы интерпретатора.532533Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.534535[`PyEval_RestoreThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_RestoreThread) – функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).536537#### `void PyEval_ReleaseThread(PyThreadState *tstate)`538539*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*540541Открепляет [прикреплённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Аргумент *tstate*, который не должен быть `NULL`, используется только для проверки того, что он представляет прикреплённое состояние потока – если это не так, сообщается о фатальной ошибке.542543[`PyEval_SaveThread()`](https://python-all.ru/3.16/c-api/threads.html#c.PyEval_SaveThread) – функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).544545# Асинхронные уведомления546547Предоставляется механизм для асинхронных уведомлений основному потоку интерпретатора. Эти уведомления имеют форму указателя на функцию и аргумента в виде указателя void.548549#### `int Py_AddPendingCall(int (*func)(void*), void *arg)`550551*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*552553Планирует вызов функции из основного потока интерпретатора. В случае успеха возвращается `0`, и *func* помещается в очередь для вызова в основном потоке. В случае неудачи возвращается `-1` без установки какого-либо исключения.554555При успешной постановке в очередь *func* будет *в конечном итоге* вызвана из основного потока интерпретатора с аргументом *arg*. Она будет вызвана асинхронно по отношению к нормально выполняющемуся коду Python, но при соблюдении обоих этих условий:556557- на границе [байткода](https://python-all.ru/3.16/glossary.html#term-bytecode);558- при удержании основным потоком [присоединённого состояния потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) (поэтому *func* может использовать полный C API).559560*func* должна возвращать `0` при успехе или `-1` при неудаче с установленным исключением. *func* не будет прервана для выполнения другого асинхронного уведомления рекурсивно, но всё же может быть прервана для переключения потоков, если [состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state) отсоединено.561562Эта функция не требует [присоединённого состояния потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Однако для вызова этой функции в подынтерпретаторе вызывающий должен иметь присоединённое состояние потока. В противном случае функция *func* может быть запланирована для вызова из неправильного интерпретатора.563564> **Предупреждение**565>566> Это низкоуровневая функция, полезная только в особых случаях. Нет гарантии, что *func* будет вызвана так быстро, насколько это возможно. Если основной поток занят выполнением системного вызова, *func* не будет вызвана до возврата из системного вызова. Эта функция в целом **не** подходит для вызова кода Python из произвольных потоков C. Вместо этого используйте [`PyThreadState_EnsureFromView()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThreadState_EnsureFromView).567568Добавлено в версии 3.1.569570Изменено в версии 3.9: Если эта функция вызывается в подынтерпретаторе, функция *func* теперь планируется для вызова из подынтерпретатора, а не из основного интерпретатора. Каждый подынтерпретатор теперь имеет свой собственный список запланированных вызовов.571572Изменено в версии 3.12: Эта функция теперь всегда планирует выполнение *func* в основном интерпретаторе.573574#### `int Py_MakePendingCalls(void)`575576*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*577578Выполняет все отложенные вызовы. Обычно это выполняется автоматически интерпретатором.579580Эта функция возвращает `0` при успехе и `-1` с установленным исключением при ошибке.581582Если эта функция вызывается не в основном потоке главного интерпретатора, она ничего не делает и возвращает `0`. Вызывающий должен удерживать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).583584Добавлено в версии 3.1.585586Изменено в версии 3.12: Эта функция выполняет отложенные вызовы только в основном интерпретаторе.587588#### `int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)`589590*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*591592Планирует асинхронное возбуждение исключения в потоке. Если в потоке уже было запланировано исключение, оно перезаписывается.593594Аргумент *id* – это идентификатор потока целевого потока, как возвращается [`PyThread_get_thread_ident()`](https://python-all.ru/3.16/c-api/threads.html#c.PyThread_get_thread_ident). *exc* – это класс возбуждаемого исключения или `NULL` для очистки отложенного исключения (если есть).595596Возвращает количество затронутых состояний потоков. Обычно это `1`, если *id* найден, даже если никаких изменений не было сделано (заданное *exc* уже было отложено, или *exc* равен `NULL`, но никакое исключение не отложено). Если идентификатор потока не найден, возвращает `0`. Это не возбуждает исключений.597598Чтобы предотвратить наивное неправильное использование, необходимо написать собственное расширение C для вызова этой функции. Эта функция должна вызываться с [присоединённым состоянием потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state). Эта функция не [похищает](https://python-all.ru/3.16/glossary.html#term-steal) никакие ссылки на *exc*. Эта функция не обязательно прерывает системные вызовы, такие как [`sleep()`](https://python-all.ru/3.16/library/time.html#time.sleep).599600Изменено в версии 3.7: Тип параметра *id* изменён с long на unsigned long.601602# API потоков операционной системы603604#### `PYTHREAD_INVALID_THREAD_ID`605606Страж-значение для недопустимого идентификатора потока.607608В настоящее время это эквивалентно `(unsigned long)-1`.609610#### `unsigned long PyThread_start_new_thread(void (*func)(void*), void *arg)`611612*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*613614Запускает функцию *func* в новом потоке с аргументом *arg*. Полученный поток не предназначен для ожидания завершения.615616*func* не должна быть `NULL`, но *arg* может быть `NULL`.617618При успехе эта функция возвращает идентификатор нового потока; при неудаче возвращает [`PYTHREAD_INVALID_THREAD_ID`](https://python-all.ru/3.16/c-api/threads.html#c.PYTHREAD_INVALID_THREAD_ID).619620Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).621622#### `unsigned long PyThread_get_thread_ident(void)`623624*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*625626Возвращает идентификатор текущего потока, который никогда не будет равен нулю.627628Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).629630> **См. также**631>632> [`threading.get_ident()`](https://python-all.ru/3.16/library/threading.html#threading.get_ident) и [`threading.Thread.ident`](https://python-all.ru/3.16/library/threading.html#threading.Thread.ident) предоставляют этот идентификатор в Python.633634#### `PyObject *PyThread_GetInfo(void)`635636*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) начиная с версии 3.3.*637638Получает общую информацию о текущем потоке в виде объекта [структурной последовательности](https://python-all.ru/3.16/c-api/tuple.html#struct-sequence-objects). Эта информация доступна как [`sys.thread_info`](https://python-all.ru/3.16/library/sys.html#sys.thread_info) в Python.639640В случае успеха возвращается новая [сильная ссылка](https://python-all.ru/3.16/glossary.html#term-strong-reference) на информацию о потоке; в случае неудачи возвращается `NULL` с установленным исключением.641642Вызывающий код должен удерживать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).643644#### `PY_HAVE_THREAD_NATIVE_ID`645646Этот макрос определён, когда система поддерживает нативные идентификаторы потоков.647648#### `unsigned long PyThread_get_thread_native_id(void)`649650*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable) на платформах с нативными идентификаторами потоков.*651652Возвращает нативный идентификатор текущего потока, назначенный ядром операционной системы; это значение никогда не бывает меньше нуля.653654Эта функция доступна, только если определён [`PY_HAVE_THREAD_NATIVE_ID`](https://python-all.ru/3.16/c-api/threads.html#c.PY_HAVE_THREAD_NATIVE_ID).655656Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).657658> **См. также**659>660> [`threading.get_native_id()`](https://python-all.ru/3.16/library/threading.html#threading.get_native_id)661662#### `void PyThread_exit_thread(void)`663664*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*665666Завершает текущий поток. Эта функция обычно считается небезопасной, и её следует избегать. Она сохранена исключительно для обратной совместимости.667668Эту функцию безопасно вызывать, только если все функции в полном стеке вызовов написаны так, чтобы допускать это безопасно.669670> **Предупреждение**671>672> Если текущая система использует потоки POSIX (также известные как «pthreads»), эта функция вызывает *[pthread\_exit(3)](https://python-all.ru/3.16/c-api/threads.html)*, которая пытается развернуть стек и вызвать деструкторы C++ в некоторых реализациях libc. Однако, если достигается функция `noexcept`, это может завершить процесс. Другие системы, такие как macOS, выполняют развёртывание.673>674> В Windows эта функция вызывает `_endthreadex()`, которая уничтожает поток без вызова деструкторов C++.675>676> В любом случае существует риск повреждения стека потока.677678Устарело с версии 3.14.679680#### `void PyThread_init_thread(void)`681682*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*683684Инициализирует API `PyThread*`. Python выполняет эту функцию автоматически, поэтому нет особой необходимости вызывать её из расширяющего модуля.685686#### `int PyThread_set_stacksize(size_t size)`687688*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*689690Устанавливает размер стека текущего потока в *size* байт.691692Эта функция возвращает `0` при успехе, `-1`, если *size* некорректен, или `-2`, если система не поддерживает изменение размера стека. Эта функция не устанавливает исключения.693694Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).695696#### `size_t PyThread_get_stacksize(void)`697698*Часть [Stable ABI](https://python-all.ru/3.16/c-api/stable.html#stable).*699700Возвращает размер стека текущего потока в байтах или `0`, если используется размер стека по умолчанию для системы.701702Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3.16/glossary.html#term-attached-thread-state).703