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

threads.md

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

1> **Источник:** https://python-all.ru/3/c-api/threads.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Состояния потоков и глобальная блокировка интерпретатора89За исключением [сборки со свободной многопоточностью](https://python-all.ru/3/glossary.html#term-free-threaded-build) [CPython](https://python-all.ru/3/glossary.html#term-CPython), интерпретатор Python в целом не является потокобезопасным. Для поддержки многопоточных программ на Python существует глобальная блокировка, называемая [глобальной блокировкой интерпретатора](https://python-all.ru/3/glossary.html#term-global-interpreter-lock), или [GIL](https://python-all.ru/3/glossary.html#term-GIL), которую поток должен захватить перед доступом к объектам Python. Без этой блокировки даже простейшие операции могут вызвать проблемы в многопоточной программе: например, если два потока одновременно увеличивают счётчик ссылок одного и того же объекта, счётчик может увеличиться только один раз вместо двух.1011Таким образом, только поток, удерживающий GIL, может работать с объектами Python или вызывать C API Python.1213Для эмуляции параллелизма интерпретатор регулярно пытается переключать потоки между инструкциями байт-кода (см. [`sys.setswitchinterval()`](https://python-all.ru/3/library/sys.html#sys.setswitchinterval)). Поэтому блокировки также необходимы для потокобезопасности в коде на чистом Python.1415Кроме того, глобальная блокировка интерпретатора освобождается вокруг блокирующих операций ввода-вывода, таких как чтение или запись в файл. В C API это делается с помощью [отсоединения состояния потока](https://python-all.ru/3/c-api/threads.html#detaching-thread-state).1617Интерпретатор Python хранит некоторую локальную для потока информацию внутри структуры данных, называемой [`PyThreadState`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState), известной как [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state). Каждый поток имеет указатель, локальный для потока, на `PyThreadState`; состояние потока, на которое ссылается этот указатель, считается [присоединённым](https://python-all.ru/3/glossary.html#term-attached-thread-state).1819Поток может иметь только одно [присоединённое состояние потока](https://python-all.ru/3/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/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) или в новом потоке, поток не будет иметь присоединённого состояния потока. Если есть сомнения, проверьте, возвращает ли [`PyThreadState_GetUnchecked()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_GetUnchecked) `NULL`.2627Если всё же потребуется создать состояние потока, вызовите [`PyThreadState_New()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_New), затем [`PyThreadState_Swap()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Swap), или воспользуйтесь опасной функцией [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure).2829## Отсоединение состояния потока из кода расширения3031Большая часть кода расширения, работающего с [состоянием потока](https://python-all.ru/3/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/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) открывает новый блок и объявляет скрытую локальную переменную; макрос [`Py_END_ALLOW_THREADS`](https://python-all.ru/3/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/c-api/threads.html#c.PyEval_SaveThread), и результат сохраняется в локальной переменной.6263Отсоединяя состояние потока, GIL освобождается, что позволяет другим потокам присоединиться к интерпретатору и выполняться, пока текущий поток выполняет блокирующий ввод-вывод. Когда операция ввода-вывода завершается, старое состояние потока повторно присоединяется вызовом [`PyEval_RestoreThread()`](https://python-all.ru/3/c-api/threads.html#c.PyEval_RestoreThread), который будет ожидать, пока не удастся захватить GIL.6465> **Примечание**66>67> Выполнение блокирующего ввода-вывода – самый распространённый случай применения отсоединения состояния потока, но его также полезно вызывать в длительном нативном коде, которому не нужен доступ к объектам Python или C API Python. Например, стандартные модули [`zlib`](https://python-all.ru/3/library/zlib.html#module-zlib) и [`hashlib`](https://python-all.ru/3/library/hashlib.html#module-hashlib) отсоединяют [состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) при сжатии или хешировании данных.6869В [сборке со свободной многопоточностью](https://python-all.ru/3/glossary.html#term-free-threaded-build) [GIL](https://python-all.ru/3/glossary.html#term-GIL) обычно не рассматривается, но **отсоединение состояния потока всё равно требуется**, потому что интерпретатору периодически нужно блокировать все потоки для получения согласованного представления объектов Python без риска состояний гонки. Например, CPython в настоящее время приостанавливает все потоки на короткое время во время работы сборщика мусора.7071> **Предупреждение**72>73> Отсоединение состояния потока может привести к непредсказуемому поведению при завершении работы интерпретатора. Подробнее см. [Предостережения по поводу завершения выполнения](https://python-all.ru/3/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).7475### API7677Следующие макросы обычно используются без точки с запятой в конце; примеры использования можно найти в дистрибутиве исходного кода Python.7879> **Примечание**80>81> Эти макросы всё ещё необходимы в [сборке со свободной многопоточностью](https://python-all.ru/3/glossary.html#term-free-threaded-build) для предотвращения взаимоблокировок.8283#### `Py_BEGIN_ALLOW_THREADS`8485*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*8687Этот макрос раскрывается в `{ PyThreadState *_save; _save = PyEval_SaveThread();`. Обратите внимание, что он содержит открывающую фигурную скобку; она должна быть сопоставлена с последующим макросом [`Py_END_ALLOW_THREADS`](https://python-all.ru/3/c-api/threads.html#c.Py_END_ALLOW_THREADS). См. выше дополнительное обсуждение этого макроса.8889#### `Py_END_ALLOW_THREADS`9091*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*9293Этот макрос раскрывается в `PyEval_RestoreThread(_save); }`. Обратите внимание, что он содержит закрывающую фигурную скобку; она должна быть сопоставлена с предыдущим макросом [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS). См. выше дополнительное обсуждение этого макроса.9495#### `Py_BLOCK_THREADS`9697*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*9899Этот макрос разворачивается в `PyEval_RestoreThread(_save);`: он эквивалентен [`Py_END_ALLOW_THREADS`](https://python-all.ru/3/c-api/threads.html#c.Py_END_ALLOW_THREADS) без закрывающей фигурной скобки.100101#### `Py_UNBLOCK_THREADS`102103*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*104105Этот макрос разворачивается в `_save = PyEval_SaveThread();`: он эквивалентен [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) без открывающей фигурной скобки и объявления переменной.106107## Потоки, созданные не из Python108109Когда потоки создаются с помощью специальных Python API (таких как модуль [`threading`](https://python-all.ru/3/library/threading.html#module-threading)), состояние потока автоматически связывается с ними. Однако, когда поток создается из нативного кода (например, сторонней библиотекой с собственным управлением потоками), он не имеет прикрепленного состояния потока.110111Если нужно вызвать код Python из этих потоков (часто это будет частью колбэк-API, предоставляемого вышеупомянутой сторонней библиотекой), необходимо сначала зарегистрировать эти потоки в интерпретаторе, создав новое состояние потока и прикрепив его.112113Самый надёжный способ – использовать [`PyThreadState_New()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_New), а затем [`PyThreadState_Swap()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Swap).114115> **Примечание**116>117> `PyThreadState_New` требует аргумента, указывающего на нужный интерпретатор; такой указатель можно получить вызовом [`PyInterpreterState_Get()`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterState_Get) из кода, в котором был создан поток.118119Например:120121```c122/* Возвращаемое значение PyInterpreterState_Get() из123   функции, создавшей этот поток. */124PyInterpreterState *interp = thread_data->interp;125126/* Создаёт новое состояние потока для интерпретатора. Оно не начинается как127   присоединённым. */128PyThreadState *tstate = PyThreadState_New(interp);129130/* Присоединить состояние потока, что приведёт к захвату GIL. */131PyThreadState_Swap(tstate);132133/* Выполнить действия Python здесь. */134result = CallSomeFunction();135/* вычислить результат или обработать исключение */136137/* Уничтожить состояние потока. После этой точки API Python не допускается. */138PyThreadState_Clear(tstate);139PyThreadState_DeleteCurrent();140```141142> **Предупреждение**143>144> Если интерпретатор завершил работу до вызова `PyThreadState_Swap`, то `interp` окажется висячим указателем!145146## Устаревший API147148Ещё один распространённый способ вызова кода Python из потока, созданного не в Python, – использовать [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure), а затем вызвать [`PyGILState_Release()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Release).149150Эти функции плохо работают, когда в процессе Python существует несколько интерпретаторов. Если ни один интерпретатор Python ещё не использовался в текущем потоке (что характерно для потоков, созданных вне Python), `PyGILState_Ensure` создаст и присоединит состояние потока для «главного» интерпретатора (первого интерпретатора в процессе Python).151152Кроме того, эти функции имеют проблемы с потоко-безопасностью при завершении интерпретатора. Использование `PyGILState_Ensure` во время завершения, скорее всего, приведёт к аварийному завершению процесса.153154Использование этих функций выглядит так:155156```c157PyGILState_STATE gstate;158gstate = PyGILState_Ensure();159160/* Выполнить действия Python здесь. */161result = CallSomeFunction();162/* вычислить результат или обработать исключение */163164/* Освободить поток. После этой точки API Python не допускается. */165PyGILState_Release(gstate);166```167168## Предостережения относительно fork()169170Ещё одна важная особенность потоков – их поведение при вызове C `fork()`. На большинстве систем с `fork()` после fork процесса остаётся только тот поток, который вызвал fork. Это оказывает конкретное влияние как на обработку блокировок, так и на всё сохранённое состояние в среде выполнения CPython.171172Тот факт, что остаётся только «текущий» поток, означает, что любые блокировки, удерживаемые другими потоками, никогда не будут освобождены. Python решает эту проблему для [`os.fork()`](https://python-all.ru/3/library/os.html#os.fork), захватывая блокировки, которые он использует внутренне, перед fork и освобождая их после. Кроме того, он сбрасывает все [объекты блокировки](https://python-all.ru/3/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/c-api/sys.html#c.PyOS_AfterFork_Child) пытается сбросить необходимые блокировки, но не всегда может это сделать.173174Тот факт, что все остальные потоки исчезают, также означает, что состояние среды выполнения CPython должно быть правильно очищено, что и делает [`os.fork()`](https://python-all.ru/3/library/os.html#os.fork). Это означает завершение всех остальных объектов [`PyThreadState`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState), принадлежащих текущему интерпретатору, и всех остальных объектов [`PyInterpreterState`](https://python-all.ru/3/c-api/subinterpreters.html#c.PyInterpreterState). Из-за этого и особой природы [«главного» интерпретатора](https://python-all.ru/3/c-api/subinterpreters.html#sub-interpreter-support), `fork()` следует вызывать только в «главном» потоке этого интерпретатора, где изначально была инициализирована глобальная среда выполнения CPython. Единственное исключение – если `exec()` будет вызван сразу после.175176## Высокоуровневые API177178Это наиболее часто используемые типы и функции при написании многопоточных расширений на C.179180#### `type PyThreadState`181182*Часть [Limited API](https://python-all.ru/3/c-api/stable.html#stable) (как непрозрачная структура).*183184Эта структура данных представляет состояние одного потока. Единственный открытый элемент данных:185186#### `PyInterpreterState *interp`187188Состояние интерпретатора этого потока.189190#### `void PyEval_InitThreads()`191192*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*193194Устаревшая функция, которая ничего не делает.195196В Python 3.6 и старше эта функция создавала GIL, если его не существовало.197198Изменено в версии 3.9: Теперь функция ничего не делает.199200Изменено в версии 3.7: Теперь эта функция вызывается [`Py_Initialize()`](https://python-all.ru/3/c-api/interp-lifecycle.html#c.Py_Initialize), так что вам больше не нужно вызывать её самостоятельно.201202Изменено в версии 3.2: Эту функцию больше нельзя вызывать до [`Py_Initialize()`](https://python-all.ru/3/c-api/interp-lifecycle.html#c.Py_Initialize).203204Устарело с версии 3.9.205206#### `PyThreadState *PyEval_SaveThread()`207208*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*209210Отсоединить [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) и вернуть его. После возврата у потока не будет [состояния потока](https://python-all.ru/3/glossary.html#term-thread-state).211212#### `void PyEval_RestoreThread(PyThreadState *tstate)`213214*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*215216Установить [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) в *tstate*. Переданное [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state) **не должно** быть присоединённым, иначе произойдёт взаимоблокировка. *tstate* будет присоединён после возврата.217218> **Примечание**219>220> Вызов этой функции из потока во время завершения выполнения приведёт к зависанию потока до выхода из программы, даже если поток не был создан Python. Подробнее см. [Предостережения по поводу завершения выполнения](https://python-all.ru/3/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).221222Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.223224#### `PyThreadState *PyThreadState_Get()`225226*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*227228Возвращает [прикреплённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state). Если у потока нет прикреплённого состояния потока (например, при нахождении внутри блока [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS)), то возникает фатальная ошибка (поэтому вызывающему коду не нужно проверять `NULL`).229230См. также [`PyThreadState_GetUnchecked()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_GetUnchecked).231232#### `PyThreadState *PyThreadState_GetUnchecked()`233234Аналогично [`PyThreadState_Get()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Get), но не завершает процесс фатальной ошибкой, если значение равно NULL. Вызывающий код должен самостоятельно проверить, не является ли результат NULL.235236Добавлено в версии 3.13: В версиях Python с 3.5 по 3.12 эта функция была приватной и называлась `_PyThreadState_UncheckedGet()`.237238#### `PyThreadState *PyThreadState_Swap(PyThreadState *tstate)`239240*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*241242Устанавливает [прикреплённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) равным *tstate* и возвращает [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state), которое было прикреплено до вызова.243244Эту функцию можно безопасно вызывать без [прикреплённого состояния потока](https://python-all.ru/3/glossary.html#term-attached-thread-state); она просто вернёт `NULL`, указывая, что предыдущего состояния потока не было.245246> **См. также**247>248> [`PyEval_ReleaseThread()`](https://python-all.ru/3/c-api/threads.html#c.PyEval_ReleaseThread)249250> **Примечание**251>252> Аналогично [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure), эта функция приведёт к зависанию потока, если среда выполнения завершает работу.253254## API состояния GIL255256Следующие функции используют локальное хранилище потока и несовместимы с подынтерпретаторами:257258#### `type PyGILState_STATE`259260*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*261262Тип значения, возвращаемого [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure) и передаваемого в [`PyGILState_Release()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Release).263264#### `enumerator PyGILState_LOCKED`265266GIL уже был захвачен, когда была вызвана [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure).267268#### `enumerator PyGILState_UNLOCKED`269270GIL не был захвачен, когда была вызвана [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure).271272#### `PyGILState_STATE PyGILState_Ensure()`273274*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*275276Гарантирует, что текущий поток готов вызывать Python C API независимо от текущего состояния Python или [присоединённого состояния потока](https://python-all.ru/3/glossary.html#term-attached-thread-state). Эта функция может вызываться потоком сколько угодно раз, при условии, что каждый вызов сопровождается вызовом [`PyGILState_Release()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Release). В целом, другие потоковые API могут использоваться между вызовами [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure) и `PyGILState_Release()`, если состояние потока восстанавливается в предыдущее состояние до вызова Release(). Например, обычное использование макросов [`Py_BEGIN_ALLOW_THREADS`](https://python-all.ru/3/c-api/threads.html#c.Py_BEGIN_ALLOW_THREADS) и [`Py_END_ALLOW_THREADS`](https://python-all.ru/3/c-api/threads.html#c.Py_END_ALLOW_THREADS) допустимо.277278Возвращаемое значение – это непрозрачный «дескриптор» [присоединённого состояния потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) на момент вызова [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure), и его необходимо передать в [`PyGILState_Release()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Release), чтобы гарантировать, что Python останется в том же состоянии. Несмотря на то, что рекурсивные вызовы разрешены, эти дескрипторы *нельзя* совместно использовать – каждый уникальный вызов `PyGILState_Ensure()` должен сохранить дескриптор для своего вызова `PyGILState_Release()`.279280Когда функция возвращает управление, будет [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) и поток сможет вызывать произвольный код Python. Сбой является фатальной ошибкой.281282> **Предупреждение**283>284> Вызов этой функции во время завершения выполнения небезопасен. Это либо приведёт к зависанию потока до завершения программы, либо, в редких случаях, вызовет полный крах интерпретатора. Подробнее см. [Предостережения по поводу завершения выполнения](https://python-all.ru/3/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).285286Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.287288#### `void PyGILState_Release(PyGILState_STATE)`289290*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*291292Освобождает любые ресурсы, полученные ранее. После этого вызова состояние Python будет таким же, как до соответствующего вызова [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure) (но обычно это состояние неизвестно вызывающему, поэтому используется GILState API).293294Каждый вызов [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure) должен сопровождаться вызовом [`PyGILState_Release()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Release) в том же потоке.295296#### `PyThreadState *PyGILState_GetThisThreadState()`297298*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*299300Получает [прикреплённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) для этого потока. Может вернуть `NULL`, если на текущем потоке не использовался GILState API. Обратите внимание, что главный поток всегда имеет такое состояние потока, даже если на главном потоке не было вызова auto-thread-state. В основном это вспомогательная/диагностическая функция.301302> **Примечание**303>304> Эта функция может вернуть не-`NULL`, даже если [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state) отсоединено. Для большинства случаев предпочтительнее использовать [`PyThreadState_Get()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Get) или [`PyThreadState_GetUnchecked()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_GetUnchecked).305306> **См. также**307>308> [`PyThreadState_Get()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Get)309310#### `int PyGILState_Check()`311312Возвращает `1`, если текущий поток удерживает [GIL](https://python-all.ru/3/glossary.html#term-GIL), и `0` в противном случае. Эту функцию можно вызывать из любого потока в любое время. Только если её [состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) было инициализировано через [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure), она вернёт `1`. В основном это вспомогательная/диагностическая функция. Она может быть полезна, например, в контекстах колбэков или функций выделения памяти, когда знание того, что GIL заблокирован, может позволить вызывающему выполнять чувствительные действия или иначе вести себя по-другому.313314> **Примечание**315>316> Если текущий процесс Python когда-либо создавал подынтерпретатор, эта функция будет *всегда* возвращать `1`. Для большинства случаев предпочтительнее использовать [`PyThreadState_GetUnchecked()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_GetUnchecked).317318Добавлено в версии 3.4.319320## Низкоуровневые API321322#### `PyThreadState *PyThreadState_New(PyInterpreterState *interp)`323324*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*325326Создаёт новый объект состояния потока, принадлежащий указанному объекту интерпретатора. [Прикреплённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) не требуется.327328#### `void PyThreadState_Clear(PyThreadState *tstate)`329330*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*331332Сбрасывает всю информацию в объекте [состояния потока](https://python-all.ru/3/glossary.html#term-thread-state). *tstate* должно быть [прикреплено](https://python-all.ru/3/glossary.html#term-attached-thread-state).333334Изменено в версии 3.9: Теперь эта функция вызывает колбэк `PyThreadState.on_delete`. Ранее это происходило в [`PyThreadState_Delete()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Delete).335336Изменено в версии 3.13: Колбэк `PyThreadState.on_delete` удалён.337338#### `void PyThreadState_Delete(PyThreadState *tstate)`339340*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*341342Уничтожает объект [состояния потока](https://python-all.ru/3/glossary.html#term-thread-state). *tstate* не должно быть [прикреплено](https://python-all.ru/3/glossary.html#term-attached-thread-state) ни к какому потоку. *tstate* должно быть предварительно сброшено вызовом [`PyThreadState_Clear()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Clear).343344#### `void PyThreadState_DeleteCurrent(void)`345346Открепляет [прикреплённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) (которое должно быть предварительно сброшено вызовом [`PyThreadState_Clear()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_Clear)) и затем уничтожает его.347348После возврата никакое [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state) не будет [прикреплено](https://python-all.ru/3/glossary.html#term-attached-thread-state).349350#### `PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)`351352*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) начиная с версии 3.10.*353354Возвращает текущий кадр состояния потока Python *tstate*.355356Возвращает [сильную ссылку](https://python-all.ru/3/glossary.html#term-strong-reference). Возвращает `NULL`, если в данный момент кадр не выполняется.357358См. также [`PyEval_GetFrame()`](https://python-all.ru/3/c-api/reflection.html#c.PyEval_GetFrame).359360*tstate* не должен быть `NULL` и должен быть [прикреплён](https://python-all.ru/3/glossary.html#term-attached-thread-state).361362Добавлено в версии 3.9.363364#### `uint64_t PyThreadState_GetID(PyThreadState *tstate)`365366*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) начиная с версии 3.10.*367368Возвращает уникальный [идентификатор состояния потока](https://python-all.ru/3/glossary.html#term-thread-state) для состояния потока Python *tstate*.369370*tstate* не должен быть `NULL` и должен быть [прикреплён](https://python-all.ru/3/glossary.html#term-attached-thread-state).371372Добавлено в версии 3.9.373374#### `PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)`375376*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) начиная с версии 3.10.*377378Возвращает интерпретатор состояния потока Python *tstate*.379380*tstate* не должен быть `NULL` и должен быть [прикреплён](https://python-all.ru/3/glossary.html#term-attached-thread-state).381382Добавлено в версии 3.9.383384#### `void PyThreadState_EnterTracing(PyThreadState *tstate)`385386Приостанавливает трассировку и профилирование в состоянии потока Python *tstate*.387388Возобновляет их с помощью функции [`PyThreadState_LeaveTracing()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_LeaveTracing).389390Добавлено в версии 3.12.391392#### `void PyThreadState_LeaveTracing(PyThreadState *tstate)`393394Возобновляет трассировку и профилирование в состоянии потока Python *tstate*, приостановленные функцией [`PyThreadState_EnterTracing()`](https://python-all.ru/3/c-api/threads.html#c.PyThreadState_EnterTracing).395396См. также функции [`PyEval_SetTrace()`](https://python-all.ru/3/c-api/profiling.html#c.PyEval_SetTrace) и [`PyEval_SetProfile()`](https://python-all.ru/3/c-api/profiling.html#c.PyEval_SetProfile).397398Добавлено в версии 3.12.399400#### `int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size)`401402> *Это [нестабильное API](https://python-all.ru/3/c-api/stable.html#unstable-c-api). Оно может меняться без предупреждения в минорных версиях.*403404Устанавливает начальный адрес защиты стека и размер защиты стека состояния потока Python.405406В случае успеха возвращает `0`. В случае неудачи устанавливает исключение и возвращает `-1`.407408CPython реализует [контроль рекурсии](https://python-all.ru/3/c-api/exceptions.html#recursion) для кода на C, вызывая [`RecursionError`](https://python-all.ru/3/library/exceptions.html#RecursionError), когда замечает, что стек выполнения машины близок к переполнению. См., например, функцию [`Py_EnterRecursiveCall()`](https://python-all.ru/3/c-api/exceptions.html#c.Py_EnterRecursiveCall). Для этого ему нужно знать расположение стека текущего потока, которое он обычно получает от операционной системы. При изменении стека, например, с помощью методов переключения контекста, таких как `boost::context` библиотеки Boost, необходимо вызвать [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection), чтобы сообщить CPython об изменении.409410Необходимо вызвать [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection) либо до, либо после изменения стека. Не следует вызывать другие функции Python C API между этим вызовом и изменением стека.411412Для отмены этой операции см. [`PyUnstable_ThreadState_ResetStackProtection()`](https://python-all.ru/3/c-api/threads.html#c.PyUnstable_ThreadState_ResetStackProtection).413414Добавлено в версии 3.15.415416#### `void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)`417418> *Это [нестабильное API](https://python-all.ru/3/c-api/stable.html#unstable-c-api). Оно может меняться без предупреждения в минорных версиях.*419420Сбрасывает начальный адрес защиты стека и размер защиты стека состояния потока Python в значения по умолчанию операционной системы.421422Пояснение см. в [`PyUnstable_ThreadState_SetStackProtection()`](https://python-all.ru/3/c-api/threads.html#c.PyUnstable_ThreadState_SetStackProtection).423424Добавлено в версии 3.15.425426#### `PyObject *PyThreadState_GetDict()`427428*Возвращаемое значение: заимствованная ссылка.*429430*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*431432Возвращает словарь, в котором расширения могут хранить информацию о состоянии, специфичном для потока. Каждое расширение должно использовать уникальный ключ для хранения состояния в словаре. Эту функцию можно вызывать, когда [состояние потока](https://python-all.ru/3/glossary.html#term-thread-state) не [прикреплено](https://python-all.ru/3/glossary.html#term-attached-thread-state). Если эта функция возвращает `NULL`, никакое исключение не было возбуждено, и вызывающий должен считать, что состояние потока не прикреплено.433434#### `void PyEval_AcquireThread(PyThreadState *tstate)`435436*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*437438[Прикрепляет](https://python-all.ru/3/glossary.html#term-attached-thread-state) *tstate* к текущему потоку, который не должен быть `NULL` или уже прикреплён.439440Вызывающий поток не должен уже иметь [прикреплённого состояния потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).441442> **Примечание**443>444> Вызов этой функции из потока, когда среда выполнения завершается, приведёт к зависанию потока до выхода из программы, даже если поток не был создан Python. Подробнее см. в [Предостережения относительно завершения работы среды выполнения](https://python-all.ru/3/c-api/interp-lifecycle.html#cautions-regarding-runtime-finalization).445446Изменено в версии 3.8: Функция обновлена для согласованности с [`PyEval_RestoreThread()`](https://python-all.ru/3/c-api/threads.html#c.PyEval_RestoreThread), [`Py_END_ALLOW_THREADS()`](https://python-all.ru/3/c-api/threads.html#c.Py_END_ALLOW_THREADS) и [`PyGILState_Ensure()`](https://python-all.ru/3/c-api/threads.html#c.PyGILState_Ensure), и теперь завершает текущий поток, если вызвана во время завершения работы интерпретатора.447448Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.449450[`PyEval_RestoreThread()`](https://python-all.ru/3/c-api/threads.html#c.PyEval_RestoreThread) – функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).451452#### `void PyEval_ReleaseThread(PyThreadState *tstate)`453454*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*455456Открепляет [прикреплённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state). Аргумент *tstate*, который не должен быть `NULL`, используется только для проверки того, что он представляет прикреплённое состояние потока – если это не так, сообщается о фатальной ошибке.457458[`PyEval_SaveThread()`](https://python-all.ru/3/c-api/threads.html#c.PyEval_SaveThread) – функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).459460# Асинхронные уведомления461462Предоставляется механизм для асинхронных уведомлений основному потоку интерпретатора. Эти уведомления имеют форму указателя на функцию и аргумента в виде указателя void.463464#### `int Py_AddPendingCall(int (*func)(void*), void *arg)`465466*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*467468Планирует вызов функции из основного потока интерпретатора. В случае успеха возвращается `0`, и *func* помещается в очередь для вызова в основном потоке. В случае неудачи возвращается `-1` без установки какого-либо исключения.469470При успешной постановке в очередь *func* будет *в конечном итоге* вызвана из основного потока интерпретатора с аргументом *arg*. Она будет вызвана асинхронно по отношению к нормально выполняющемуся коду Python, но при соблюдении обоих этих условий:471472- на границе [байткода](https://python-all.ru/3/glossary.html#term-bytecode);473- при удержании основным потоком [присоединённого состояния потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) (поэтому *func* может использовать полный C API).474475*func* должна возвращать `0` при успехе или `-1` при неудаче с установленным исключением. *func* не будет прервана для выполнения другого асинхронного уведомления рекурсивно, но всё же может быть прервана для переключения потоков, если [состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state) отсоединено.476477Эта функция не требует [присоединённого состояния потока](https://python-all.ru/3/glossary.html#term-attached-thread-state). Однако для вызова этой функции в подынтерпретаторе вызывающий должен иметь присоединённое состояние потока. В противном случае функция *func* может быть запланирована для вызова из неправильного интерпретатора.478479> **Предупреждение**480>481> Это низкоуровневая функция, полезная только в особых случаях. Нет гарантии, что *func* будет вызвана максимально быстро. Если главный поток занят выполнением системного вызова, *func* не будет вызвана до возврата из системного вызова. Эта функция в целом **не** подходит для вызова кода Python из произвольных C-потоков. Вместо неё используйте [PyGILState API](https://python-all.ru/3/c-api/threads.html#gilstate).482483Добавлено в версии 3.1.484485Изменено в версии 3.9: Если эта функция вызывается в подынтерпретаторе, функция *func* теперь планируется для вызова из подынтерпретатора, а не из основного интерпретатора. Каждый подынтерпретатор теперь имеет свой собственный список запланированных вызовов.486487Изменено в версии 3.12: Эта функция теперь всегда планирует выполнение *func* в основном интерпретаторе.488489#### `int Py_MakePendingCalls(void)`490491*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*492493Выполняет все отложенные вызовы. Обычно это выполняется автоматически интерпретатором.494495Эта функция возвращает `0` при успехе и `-1` с установленным исключением при ошибке.496497Если эта функция вызывается не в основном потоке главного интерпретатора, она ничего не делает и возвращает `0`. Вызывающий должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).498499Добавлено в версии 3.1.500501Изменено в версии 3.12: Эта функция выполняет отложенные вызовы только в основном интерпретаторе.502503#### `int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)`504505*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*506507Асинхронно возбуждает исключение в потоке. Аргумент *id* – это идентификатор целевого потока; *exc* – объект исключения, которое нужно возбудить. Эта функция не [крадёт](https://python-all.ru/3/glossary.html#term-steal) ссылки на *exc*. Чтобы предотвратить наивное злоупотребление, необходимо написать собственное C-расширение для её вызова. Должна вызываться с [прикреплённым состоянием потока](https://python-all.ru/3/glossary.html#term-attached-thread-state). Возвращает количество изменённых состояний потока; обычно это единица, но будет нулём, если идентификатор потока не найден. Если *exc* равно `NULL`, ожидающее исключение (если есть) для потока очищается. Эта функция не возбуждает исключений.508509Изменено в версии 3.7: Тип параметра *id* изменён с long на unsigned long.510511# API потоков операционной системы512513#### `PYTHREAD_INVALID_THREAD_ID`514515Страж-значение для недопустимого идентификатора потока.516517В настоящее время эквивалентно `(unsigned long)-1`.518519#### `unsigned long PyThread_start_new_thread(void (*func)(void*), void *arg)`520521*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*522523Запускает функцию *func* в новом потоке с аргументом *arg*. Полученный поток не предназначен для ожидания завершения.524525*func* не должна быть `NULL`, но *arg* может быть `NULL`.526527При успехе эта функция возвращает идентификатор нового потока; при неудаче возвращает [`PYTHREAD_INVALID_THREAD_ID`](https://python-all.ru/3/c-api/threads.html#c.PYTHREAD_INVALID_THREAD_ID).528529Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).530531#### `unsigned long PyThread_get_thread_ident(void)`532533*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*534535Возвращает идентификатор текущего потока, который никогда не будет равен нулю.536537Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).538539> **См. также**540>541> [`threading.get_ident()`](https://python-all.ru/3/library/threading.html#threading.get_ident)542543#### `PyObject *PyThread_GetInfo(void)`544545*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) начиная с версии 3.3.*546547Получает общую информацию о текущем потоке в виде объекта [структурной последовательности](https://python-all.ru/3/c-api/tuple.html#struct-sequence-objects). Эта информация доступна как [`sys.thread_info`](https://python-all.ru/3/library/sys.html#sys.thread_info) в Python.548549В случае успеха возвращается новая [сильная ссылка](https://python-all.ru/3/glossary.html#term-strong-reference) на информацию о потоке; в случае неудачи возвращается `NULL` с установленным исключением.550551Вызывающий код должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).552553#### `PY_HAVE_THREAD_NATIVE_ID`554555Этот макрос определён, когда система поддерживает нативные идентификаторы потоков.556557#### `unsigned long PyThread_get_thread_native_id(void)`558559*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable) на платформах с нативными идентификаторами потоков.*560561Возвращает нативный идентификатор текущего потока, назначенный ядром операционной системы; это значение никогда не бывает меньше нуля.562563Эта функция доступна, только если определён [`PY_HAVE_THREAD_NATIVE_ID`](https://python-all.ru/3/c-api/threads.html#c.PY_HAVE_THREAD_NATIVE_ID).564565Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).566567> **См. также**568>569> [`threading.get_native_id()`](https://python-all.ru/3/library/threading.html#threading.get_native_id)570571#### `void PyThread_exit_thread(void)`572573*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*574575Завершает текущий поток. Эта функция обычно считается небезопасной, и её следует избегать. Она сохранена исключительно для обратной совместимости.576577Эту функцию безопасно вызывать, только если все функции в полном стеке вызовов написаны так, чтобы допускать это безопасно.578579> **Предупреждение**580>581> Если текущая система использует потоки POSIX (также известные как «pthreads»), эта функция вызывает *[pthread\_exit(3)](https://python-all.ru/3/c-api/threads.html)*, которая пытается развернуть стек и вызвать деструкторы C++ в некоторых реализациях libc. Однако, если достигается функция `noexcept`, это может завершить процесс. Другие системы, такие как macOS, выполняют развёртывание.582>583> В Windows эта функция вызывает `_endthreadex()`, которая уничтожает поток без вызова деструкторов C++.584>585> В любом случае существует риск повреждения стека потока.586587Устарело с версии 3.14.588589#### `void PyThread_init_thread(void)`590591*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*592593Инициализирует API `PyThread*`. Python выполняет эту функцию автоматически, поэтому нет особой необходимости вызывать её из расширяющего модуля.594595#### `int PyThread_set_stacksize(size_t size)`596597*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*598599Устанавливает размер стека текущего потока в *size* байт.600601Эта функция возвращает `0` при успехе, `-1`, если *size* некорректен, или `-2`, если система не поддерживает изменение размера стека. Эта функция не устанавливает исключения.602603Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).604605#### `size_t PyThread_get_stacksize(void)`606607*Часть [Stable ABI](https://python-all.ru/3/c-api/stable.html#stable).*608609Возвращает размер стека текущего потока в байтах или `0`, если используется размер стека по умолчанию для системы.610611Вызывающий код не должен удерживать [присоединённое состояние потока](https://python-all.ru/3/glossary.html#term-attached-thread-state).612