Содержание страницы
Состояния потоков и глобальная блокировка интерпретатора¶Thread states and the global interpreter lock
За исключением сборки со свободной многопоточностью CPython, интерпретатор Python в целом не является потокобезопасным. Для поддержки многопоточных программ на Python существует глобальная блокировка, называемая глобальной блокировкой интерпретатора, или GIL, которую поток должен захватить перед доступом к объектам Python. Без этой блокировки даже простейшие операции могут вызвать проблемы в многопоточной программе: например, если два потока одновременно увеличивают счётчик ссылок одного и того же объекта, счётчик может увеличиться только один раз вместо двух.
Таким образом, только поток, удерживающий GIL, может работать с объектами Python или вызывать C API Python.
Для эмуляции параллелизма интерпретатор регулярно пытается переключать потоки между инструкциями байт-кода (см. sys.setswitchinterval()). Поэтому блокировки также необходимы для потокобезопасности в коде на чистом Python.
Кроме того, глобальная блокировка интерпретатора освобождается вокруг блокирующих операций ввода-вывода, таких как чтение или запись в файл. В C API это делается с помощью отсоединения состояния потока.
Интерпретатор Python хранит некоторую локальную для потока информацию внутри структуры данных, называемой PyThreadState, известной как состояние потока. Каждый поток имеет указатель, локальный для потока, на PyThreadState; состояние потока, на которое ссылается этот указатель, считается присоединённым.
Поток может иметь только одно присоединённое состояние потока в каждый момент времени. Присоединённое состояние потока обычно аналогично удержанию GIL, за исключением сборок со свободной многопоточностью. В сборках с включённым GIL присоединение состояния потока будет блокироваться до тех пор, пока не будет получен GIL. Однако даже в сборках с отключённым GIL всё равно требуется иметь присоединённое состояние потока, поскольку интерпретатору необходимо отслеживать, какие потоки могут обращаться к объектам Python.
Примечание
Даже в сборке со свободной многопоточностью присоединение состояния потока может блокироваться, так как GIL может быть повторно включён, или потоки могут быть временно приостановлены (например, во время сборки мусора).
Обычно при использовании C API Python всегда есть присоединённое состояние потока, в том числе при встраивании и реализации методов, так что необходимость самостоятельно настраивать состояние потока возникает редко. Только в некоторых особых случаях, например в блоке Py_BEGIN_ALLOW_THREADS или в новом потоке, поток не будет иметь присоединённого состояния потока. Если есть сомнения, проверьте, возвращает ли PyThreadState_GetUnchecked() NULL.
Если всё же необходимо создать состояние потока, рекомендуется использовать PyThreadState_Ensure() или PyThreadState_EnsureFromView(), которые управляют состоянием потока.
Отсоединение состояния потока из кода расширения¶Detaching the thread state from extension code
Большая часть кода расширения, работающего с состоянием потока, имеет следующую простую структуру:
Save the thread state in a local variable.
... Do some blocking I/O operation ...
Restore the thread state from the local variable.
Это настолько распространено, что существует пара макросов для упрощения:
Py_BEGIN_ALLOW_THREADS
... Do some blocking I/O operation ...
Py_END_ALLOW_THREADS
Макрос Py_BEGIN_ALLOW_THREADS открывает новый блок и объявляет скрытую локальную переменную; макрос Py_END_ALLOW_THREADS закрывает блок.
Приведённый выше блок раскрывается в следующий код:
PyThreadState *_save;
_save = PyEval_SaveThread();
... Do some blocking I/O operation ...
PyEval_RestoreThread(_save);
Вот как работают эти функции:
Присоединённое состояние потока подразумевает, что GIL удерживается для интерпретатора. Чтобы отсоединить его, вызывается PyEval_SaveThread(), и результат сохраняется в локальной переменной.
Отсоединяя состояние потока, GIL освобождается, что позволяет другим потокам присоединиться к интерпретатору и выполняться, пока текущий поток выполняет блокирующий ввод-вывод. Когда операция ввода-вывода завершается, старое состояние потока повторно присоединяется вызовом PyEval_RestoreThread(), который будет ожидать, пока не удастся захватить GIL.
Примечание
Выполнение блокирующего ввода-вывода – самый распространённый случай применения отсоединения состояния потока, но его также полезно вызывать в длительном нативном коде, которому не нужен доступ к объектам Python или C API Python. Например, стандартные модули zlib и hashlib отсоединяют состояние потока при сжатии или хешировании данных.
В сборке со свободной многопоточностью GIL обычно не рассматривается, но отсоединение состояния потока всё равно требуется, потому что интерпретатору периодически нужно блокировать все потоки для получения согласованного представления объектов Python без риска состояний гонки. Например, CPython в настоящее время приостанавливает все потоки на короткое время во время работы сборщика мусора.
Предупреждение
Отсоединение состояния потока может привести к неожиданному поведению во время завершения работы интерпретатора. См. раздел Предостережения относительно завершения работы интерпретатора для получения более подробной информации.
API¶APIs
Следующие макросы обычно используются без точки с запятой в конце; примеры использования можно найти в дистрибутиве исходного кода Python.
Примечание
Эти макросы всё ещё необходимы в сборке со свободной многопоточностью для предотвращения взаимоблокировок.
-
Py_BEGIN_ALLOW_THREADS¶
- Часть Stable ABI.
Этот макрос раскрывается в
{ PyThreadState *_save; _save = PyEval_SaveThread();. Обратите внимание, что он содержит открывающую фигурную скобку; она должна быть сопоставлена с последующим макросомPy_END_ALLOW_THREADS. См. выше дополнительное обсуждение этого макроса.
-
Py_END_ALLOW_THREADS¶
- Часть Stable ABI.
Этот макрос раскрывается в
PyEval_RestoreThread(_save); }. Обратите внимание, что он содержит закрывающую фигурную скобку; она должна быть сопоставлена с предыдущим макросомPy_BEGIN_ALLOW_THREADS. См. выше дополнительное обсуждение этого макроса.
-
Py_BLOCK_THREADS¶
- Часть Stable ABI.
Этот макрос разворачивается в
PyEval_RestoreThread(_save);: он эквивалентенPy_END_ALLOW_THREADSбез закрывающей фигурной скобки.
-
Py_UNBLOCK_THREADS¶
- Часть Stable ABI.
Этот макрос разворачивается в
_save = PyEval_SaveThread();: он эквивалентенPy_BEGIN_ALLOW_THREADSбез открывающей фигурной скобки и объявления переменной.
Использование C API из внешних потоков¶Using the C API from foreign threads
Когда потоки создаются с помощью специальных Python API (таких как модуль threading), состояние потока автоматически связывается с ними.
Однако, когда поток создается из нативного кода (например, сторонней библиотекой с собственным управлением потоками), он не имеет прикрепленного состояния потока.
Если нужно вызвать код Python из этих потоков (часто это будет частью колбэк-API, предоставляемого вышеупомянутой сторонней библиотекой), необходимо сначала зарегистрировать эти потоки в интерпретаторе, создав новое состояние потока и прикрепив его.
Самый простой способ сделать это – через PyThreadState_Ensure()
или PyThreadState_EnsureFromView().
Примечание
Эти функции требуют аргумент, указывающий на нужный
интерпретатор; такой указатель можно получить вызовом
PyInterpreterGuard_FromCurrent() (для PyThreadState_Ensure) или
PyInterpreterView_FromCurrent() (для PyThreadState_EnsureFromView)
из функции, создающей поток. Если указатель недоступен (например,
когда заданная нативная библиотека потоков не предоставляет аргумент data),
можно использовать PyInterpreterView_FromMain() для получения представления главного
интерпретатора, но учтите, что это сделает код несовместимым с
субинтерпретаторами.
Например:
// Возвращаемое значение PyInterpreterGuard_FromCurrent() из
// функции, создавшей этот поток.
PyInterpreterGuard *guard = thread_data->guard;
// Создаёт новое состояние потока для интерпретатора.
PyThreadStateToken *token = PyThreadState_Ensure(guard);
if (token == NULL) {
PyInterpreterGuard_Close(guard);
return;
}
// Имеется корректное состояние потока – выполните здесь действия Python.
result = CallSomeFunction();
// Вычислить результат или обработать исключения.
// Освободить состояние потока. Вызовы C API не допускаются после этой
// точки.
PyThreadState_Release(token);
PyInterpreterGuard_Close(guard);
Имейте в виду, что вызов PyThreadState_Ensure не всегда создает новое
состояние потока, а вызов PyThreadState_Release не всегда его отсоединяет.
Эти функции могут повторно использовать существующее прикрепленное состояние потока или повторно прикрепить
состояние потока, которое ранее было прикреплено для текущего потока.
См. также
Повторное использование состояния потока при многократных вызовах¶Reusing a thread state across repeated calls
Создание и уничтожение PyThreadState небесплатно и стоит дороже
на сборке со свободными потоками. Внешний поток, много раз вызывающий
интерпретатор – например, рабочий поток в нативном пуле потоков –
должен избегать создания нового состояния потока при каждом входе и
уничтожения его при каждом выходе. Вместо этого следует настроить одно состояние потока при запуске
потока (или лениво при его первом вызове в Python), прикреплять и отсоединять его вокруг
каждого вызова и один раз уничтожить, когда поток завершается.
Управляйте состоянием потока явно с помощью PyThreadState_New(), прикрепляя
и отсоединяя его с помощью PyEval_RestoreThread() и
PyEval_SaveThread(). Это происходит в три отдельных этапа, в
разные моменты жизни потока.
Когда поток запускается, создайте одно состояние потока для него. interp – это
целевой интерпретатор, захваченный кодом, создавшим этот поток, пока у него было
прикрепленное состояние потока (например, через PyInterpreterState_Get()):
PyThreadState *tstate = PyThreadState_New(interp);
Затем при каждом вызове Python – который может происходить много раз в течение жизни потока – прикрепите состояние потока, выполните вызовы C API Python, требующие его, и снова отсоедините, чтобы поток не удерживал GIL, когда занимается не-Python работой:
PyEval_RestoreThread(tstate);
result = CallSomeFunction(); /* Здесь размещаются ваши вызовы Python C API. */
PyEval_SaveThread();
Когда поток завершит вызовы в Python, уничтожьте состояние потока один раз:
PyEval_RestoreThread(tstate);
PyThreadState_Clear(tstate);
PyThreadState_DeleteCurrent();
Универсальные точки входа для вызова из внешнего потока –
PyThreadState_Ensure() и старая PyGILState_Ensure() – не гарантируют постоянное состояние потока: время жизни их состояния потока
намеренно определено реализацией, поэтому пара acquire/release может
создавать и уничтожать состояние потока каждый раз. Используйте PyThreadState_New(),
как показано здесь, когда необходимо повторно использовать одно состояние потока при
вызовах.
Код, создавший внешний поток, должен организовать выполнение последовательности завершения
до выхода потока и до вызова Py_FinalizeEx().
Если сначала начнется финализация интерпретатора, вызов shutdown
PyEval_RestoreThread() зависнет, а не вернется (см.
Предостережения относительно финализации интерпретатора). Если поток завершится без
выполнения последовательности завершения, состояние потока будет утечено на оставшееся время
процесса.
Прикрепление/отсоединение состояний потоков¶Attaching/detaching thread states
-
PyThreadStateToken *PyThreadState_Ensure(PyInterpreterGuard *guard)¶
- Часть Stable ABI начиная с версии 3.15.
Гарантирует, что поток имеет прикрепленное состояние потока для интерпретатора, защищенного guard, и поэтому может безопасно вызывать этот интерпретатор.
Вызов этой функции допустим, если поток уже имеет прикрепленное состояние потока, при условии, что последует вызов
PyThreadState_Release(), соответствующий этому (то есть разрешены “вложенные” вызовы этой функции).Эффект функции (если он есть) будет отменен соответствующим вызовом
PyThreadState_Release().В случае ошибки эта функция возвращает
NULLбез установленного исключения. Не вызывайтеPyThreadState_Release()в этом случае.При успехе эта функция возвращает значение указателя, которое должно быть передано в соответствующий вызов
PyThreadState_Release().Условия, при которых эта функция создает новое состояние потока, считаются нестабильными и зависящими от реализации. Если необходимо управлять точным временем жизни состояния потока, рассмотрите использование
PyThreadState_New(). Однако не избегайте этой функции только на том основании, что время жизни состояния потока может быть несовместимым между версиями; изменения в этой функции будут проводиться с осторожностью и обратно совместимым образом. В частности, сохранение локальных переменных потока и аналогичного состояния будет сохранено между версиями Python.Деталь реализации CPython: Точное поведение относительно того, создает ли эта функция новое состояние потока, описано ниже, но имейте в виду, что это может измениться в будущем.
Сначала функция проверяет, присутствует ли прикрепленное состояние потока. Если да, функция проверяет, совпадает ли интерпретатор этого состояния потока с интерпретатором, защищенным guard. Если это так, функция просто помечает состояние потока как используемое вызовом
PyThreadState_Ensureи возвращается.Если прикрепленного состояния потока нет, функция проверяет, использовалось ли какое-либо состояние потока текущим потоком ОС. (Это возвращается
PyGILState_GetThisThreadState().) Если да, функция проверяет, совпадает ли интерпретатор этого состояния потока с guard. Если совпадает, оно повторно прикрепляется и помечается как используемое.В противном случае, если оба вышеуказанных случая не сработали, создается новое состояние потока для guard. Затем оно прикрепляется и помечается как принадлежащее
PyThreadState_Ensure.Добавлено в версии 3.15.
-
PyThreadStateToken *PyThreadState_EnsureFromView(PyInterpreterView *view)¶
- Часть Stable ABI начиная с версии 3.15.
Получить присоединённое состояние потока для интерпретатора, на который ссылается view.
Поведение и возвращаемое значение такие же, как для
PyThreadState_Ensure(); дополнительно, если функция завершается успешно, интерпретатор, на который ссылается view, будет неявно защищён. Защита будет снята при соответствующем вызовеPyThreadState_Release().Добавлено в версии 3.15.
-
void PyThreadState_Release(PyThreadStateToken *token)¶
- Часть Stable ABI начиная с версии 3.15.
Отменить вызов
PyThreadState_Ensure()илиPyThreadState_EnsureFromView().Эта функция должна вызываться ровно один раз для каждого успешного вызова Ensure, при этом token должен быть установлен в возвращаемое значение этого вызова.
Состояние, которое было присоединено до соответствующего вызова Ensure (если таковое имелось), будет присоединено снова, когда
PyThreadState_Release()вернёт управление.Точное поведение того, удаляет ли эта функция состояние потока, считается нестабильным и зависит от реализации.
Особенность реализации CPython: В настоящее время эта функция уменьшает внутренний счётчик присоединённого состояния потока. Если этот счётчик когда-либо опускается ниже нуля, функция вызывает фатальную ошибку (через
Py_FatalError()).Если присоединённое состояние потока принадлежит
PyThreadState_Ensure, то оно будет освобождено и удалено, когда внутренний счётчик достигнет нуля. В противном случае при достижении счётчиком нуля ничего не происходит.Добавлено в версии 3.15.
-
type PyThreadStateToken¶
- Часть Stable ABI (как непрозрачная структура) начиная с версии 3.15.
Непрозрачный токен, полученный из вызова
PyThreadState_Ensure()и переданный в соответствующий вызовPyThreadState_Release().
API состояния GIL¶GIL-state APIs
Следующие API в целом несовместимы с подынтерпретаторами и приведут к зависанию процесса во время финализации интерпретатора (см. Предостережения относительно финализации интерпретатора). Поэтому эти API были мягко устарели в Python 3.15 в пользу новых API.
-
type PyGILState_STATE¶
- Часть Stable ABI.
Тип значения, возвращаемого
PyGILState_Ensure()и передаваемого вPyGILState_Release().-
enumerator PyGILState_LOCKED¶
GIL уже был захвачен, когда была вызвана
PyGILState_Ensure().
-
enumerator PyGILState_UNLOCKED¶
GIL не был захвачен, когда была вызвана
PyGILState_Ensure().
-
enumerator PyGILState_LOCKED¶
-
PyGILState_STATE PyGILState_Ensure()¶
- Часть Stable ABI.
Гарантирует, что текущий поток готов вызывать Python C API независимо от текущего состояния Python или присоединённого состояния потока. Эта функция может вызываться потоком сколько угодно раз, при условии, что каждый вызов сопровождается вызовом
PyGILState_Release(). В целом, другие потоковые API могут использоваться между вызовамиPyGILState_Ensure()иPyGILState_Release(), если состояние потока восстанавливается в предыдущее состояние до вызова Release(). Например, обычное использование макросовPy_BEGIN_ALLOW_THREADSиPy_END_ALLOW_THREADSдопустимо.Возвращаемое значение – это непрозрачный «дескриптор» присоединённого состояния потока на момент вызова
PyGILState_Ensure(), и его необходимо передать вPyGILState_Release(), чтобы гарантировать, что Python останется в том же состоянии. Несмотря на то, что рекурсивные вызовы разрешены, эти дескрипторы нельзя совместно использовать – каждый уникальный вызовPyGILState_Ensure()должен сохранить дескриптор для своего вызоваPyGILState_Release().После возврата функции будет существовать присоединённое состояние потока, и поток сможет вызывать произвольный код Python.
У этой функции нет способа вернуть ошибку. Поэтому ошибки либо фатальны (то есть они отправляют
SIGABRTи аварийно завершают процесс; см.Py_FatalError()), либо поток будет заблокирован бессрочно (например, во время финализации интерпретатора).Предупреждение
Вызов этой функции во время финализации интерпретатора приведёт к бесконечному зависанию потока, что может вызвать взаимоблокировки. Предостережения относительно финализации интерпретатора для подробностей.
Кроме того, эта функция в целом не работает с подынтерпретаторами при использовании из внешних потоков, так как у неё нет способа узнать, какой интерпретатор создал поток (и поэтому она неявно выбирает главный интерпретатор).
Изменено в версии 3.14: При вызове во время финализации интерпретатора теперь зависает текущий поток, а не завершает его.
Мягко устарело начиная с версии 3.15: Используйте
PyThreadState_Ensure()илиPyThreadState_EnsureFromView()вместо него.
-
void PyGILState_Release(PyGILState_STATE)¶
- Часть Stable ABI.
Освобождает все ранее приобретённые ресурсы. После этого вызова состояние Python будет таким же, как до соответствующего вызова
PyGILState_Ensure()(но обычно это состояние неизвестно вызывающей стороне, поэтому и используется API состояния GIL).Каждый вызов
PyGILState_Ensure()должен сопровождаться вызовомPyGILState_Release()в том же потоке.Мягко устарело начиная с версии 3.15: Используйте
PyThreadState_Release()вместо него.
-
PyThreadState *PyGILState_GetThisThreadState()¶
- Часть Stable ABI.
Получить состояние потока, которое последним было присоединено для этого потока. (Если последнее состояние потока было удалено, эта функция возвращает
NULL.)Если у вызывающего есть присоединённое состояние потока, оно возвращается.
Другими словами, эта функция возвращает состояние потока, которое будет использовано
PyGILState_Ensure(). Если она возвращаетNULL, тоPyGILState_Ensureсоздаёт новое состояние потока.Эта функция не может завершиться с ошибкой.
Мягко устарело начиная с версии 3.15: Вместо этого используйте
PyThreadState_Get()илиPyThreadState_GetUnchecked().
-
int PyGILState_Check()¶
Возвращает
1, если текущий поток имеет присоединённое состояние потока, которое совпадает с состоянием потока, возвращаемымPyGILState_GetThisThreadState(). Если у вызывающего нет присоединённого состояния потока или оно не совпадает, то возвращается0.Если текущий процесс Python когда-либо создавал суб-интерпретатор, эта функция будет всегда возвращать
1.Это в основном вспомогательная/диагностическая функция.
Добавлено в версии 3.4.
Мягко устарело начиная с версии 3.15: Вместо этого используйте
PyThreadState_GetUnchecked() != NULL.
Предостережения относительно fork()¶Cautions about fork()
Ещё одна важная особенность потоков – их поведение при вызове C fork(). На большинстве систем с fork() после
fork процесса остаётся только тот поток, который вызвал fork. Это
оказывает конкретное влияние как на обработку блокировок, так и на всё сохранённое состояние
в среде выполнения CPython.
Тот факт, что остаётся только «текущий» поток, означает, что любые блокировки, удерживаемые другими потоками, никогда не будут освобождены. Python решает эту проблему для os.fork(), захватывая блокировки, которые он использует внутренне, перед fork и освобождая их после. Кроме того, он сбрасывает все
объекты блокировки в дочернем процессе. При расширении или встраивании Python нет способа сообщить Python о дополнительных (не-Python) блокировках, которые необходимо захватить перед fork или сбросить после него. Для достижения того же эффекта потребуется использовать системные механизмы, такие как
pthread_atfork().
Кроме того, при расширении или встраивании Python вызов fork() напрямую, а не через os.fork() (и возврат к вызову Python) может привести к взаимоблокировке из-за того, что одна из внутренних блокировок Python удерживается потоком, который становится недействительным после fork.
PyOS_AfterFork_Child() пытается сбросить необходимые блокировки, но не всегда может это сделать.
Тот факт, что все остальные потоки исчезают, также означает, что состояние среды выполнения CPython должно быть правильно очищено, что и делает os.fork(). Это означает завершение всех остальных объектов PyThreadState, принадлежащих текущему интерпретатору, и всех остальных объектов PyInterpreterState. Из-за этого и особой природы «главного» интерпретатора, fork() следует вызывать только в «главном» потоке этого интерпретатора, где изначально была инициализирована глобальная среда выполнения CPython. Единственное исключение – если exec() будет вызван сразу после.
API высокого уровня¶High-level APIs
Это наиболее часто используемые типы и функции при написании многопоточных расширений на C.
-
type PyThreadState¶
- Часть Stable ABI (как непрозрачная структура).
Эта структура данных представляет состояние одного потока. Единственный открытый элемент данных:
-
PyInterpreterState *interp¶
Состояние интерпретатора этого потока.
-
PyInterpreterState *interp¶
-
void PyEval_InitThreads()¶
- Часть Stable ABI.
Устаревшая функция, которая ничего не делает.
В Python 3.6 и старше эта функция создавала GIL, если его не существовало.
Изменено в версии 3.9: Теперь функция ничего не делает.
Изменено в версии 3.7: Теперь эта функция вызывается
Py_Initialize(), так что вам больше не нужно вызывать её самостоятельно.Изменено в версии 3.2: Эту функцию больше нельзя вызывать до
Py_Initialize().Устарело с версии 3.9.
-
PyThreadState *PyEval_SaveThread()¶
- Часть Stable ABI.
Отсоединить присоединённое состояние потока и вернуть его. После возврата у потока не будет состояния потока.
-
void PyEval_RestoreThread(PyThreadState *tstate)¶
- Часть Stable ABI.
Установить присоединённое состояние потока в tstate. Переданное состояние потока не должно быть присоединённым, иначе произойдёт взаимоблокировка. tstate будет присоединён после возврата.
Примечание
Вызов этой функции из потока во время завершения работы среды выполнения приведёт к зависанию потока до выхода из программы, даже если поток не был создан Python. Подробнее см. Предостережения относительно завершения работы интерпретатора.
Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.
-
PyThreadState *PyThreadState_Get()¶
- Часть Stable ABI.
Возвращает прикреплённое состояние потока. Если у потока нет прикреплённого состояния потока (например, при нахождении внутри блока
Py_BEGIN_ALLOW_THREADS), то возникает фатальная ошибка (поэтому вызывающему коду не нужно проверятьNULL).См. также
PyThreadState_GetUnchecked().
-
PyThreadState *PyThreadState_GetUnchecked()¶
Аналогично
PyThreadState_Get(), но не завершает процесс фатальной ошибкой, если значение равно NULL. Вызывающий код должен самостоятельно проверить, не является ли результат NULL.Добавлено в версии 3.13: В версиях Python с 3.5 по 3.12 эта функция была приватной и называлась
_PyThreadState_UncheckedGet().
-
PyThreadState *PyThreadState_Swap(PyThreadState *tstate)¶
- Часть Stable ABI.
Устанавливает прикреплённое состояние потока равным tstate и возвращает состояние потока, которое было прикреплено до вызова.
Эту функцию можно безопасно вызывать без прикреплённого состояния потока; она просто вернёт
NULL, указывая, что предыдущего состояния потока не было.См. также
Примечание
Аналогично
PyGILState_Ensure(), эта функция приведёт к зависанию потока, если среда выполнения завершает работу.
Низкоуровневые API¶Low-level APIs
-
PyThreadState *PyThreadState_New(PyInterpreterState *interp)¶
- Часть Stable ABI.
Создаёт новый объект состояния потока, принадлежащий указанному объекту интерпретатора. Прикреплённое состояние потока не требуется.
-
void PyThreadState_Clear(PyThreadState *tstate)¶
- Часть Stable ABI.
Сбрасывает всю информацию в объекте состояния потока. tstate должно быть прикреплено.
Изменено в версии 3.9: Теперь эта функция вызывает колбэк
PyThreadState.on_delete. Ранее это происходило вPyThreadState_Delete().Изменено в версии 3.13: Колбэк
PyThreadState.on_deleteудалён.
-
void PyThreadState_Delete(PyThreadState *tstate)¶
- Часть Stable ABI.
Уничтожает объект состояния потока. tstate не должно быть прикреплено ни к какому потоку. tstate должно быть предварительно сброшено вызовом
PyThreadState_Clear().
-
void PyThreadState_DeleteCurrent(void)¶
Открепляет прикреплённое состояние потока (которое должно быть предварительно сброшено вызовом
PyThreadState_Clear()) и затем уничтожает его.После возврата никакое состояние потока не будет прикреплено.
-
PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)¶
- Часть Stable ABI начиная с версии 3.10.
Возвращает текущий кадр состояния потока Python tstate.
Возвращает сильную ссылку. Возвращает
NULL, если в данный момент кадр не выполняется.См. также
PyEval_GetFrame().tstate не должно быть
NULLи должно быть прикреплено.Добавлено в версии 3.9.
-
uint64_t PyThreadState_GetID(PyThreadState *tstate)¶
- Часть Stable ABI начиная с версии 3.10.
Возвращает уникальный идентификатор состояния потока для состояния потока Python tstate.
tstate не должно быть
NULLи должно быть прикреплено.Добавлено в версии 3.9.
-
PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)¶
- Часть Stable ABI начиная с версии 3.10.
Возвращает интерпретатор состояния потока Python tstate.
tstate не должен быть
NULLи должен быть прикреплён.Добавлено в версии 3.9.
-
void PyThreadState_EnterTracing(PyThreadState *tstate)¶
Приостанавливает трассировку и профилирование в состоянии потока Python tstate.
Возобновляет их с помощью функции
PyThreadState_LeaveTracing().Добавлено в версии 3.12.
-
void PyThreadState_LeaveTracing(PyThreadState *tstate)¶
Возобновляет трассировку и профилирование в состоянии потока Python tstate, приостановленные функцией
PyThreadState_EnterTracing().См. также функции
PyEval_SetTrace()иPyEval_SetProfile().Добавлено в версии 3.12.
-
int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size)¶
- Это нестабильное API. Оно может меняться без предупреждения в минорных версиях.
Устанавливает начальный адрес защиты стека и размер защиты стека состояния потока Python.
В случае успеха возвращает
0. В случае неудачи устанавливает исключение и возвращает-1.CPython реализует контроль рекурсии для кода на C, вызывая
RecursionError, когда замечает, что стек выполнения машины близок к переполнению. См., например, функциюPy_EnterRecursiveCall(). Для этого ему нужно знать расположение стека текущего потока, которое он обычно получает от операционной системы. При изменении стека, например, с помощью методов переключения контекста, таких какboost::contextбиблиотеки Boost, необходимо вызватьPyUnstable_ThreadState_SetStackProtection(), чтобы сообщить CPython об изменении.Необходимо вызвать
PyUnstable_ThreadState_SetStackProtection()либо до, либо после изменения стека. Не следует вызывать другие функции Python C API между этим вызовом и изменением стека.Для отмены этой операции см.
PyUnstable_ThreadState_ResetStackProtection().Добавлено в версии 3.15.
-
void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)¶
- Это нестабильное API. Оно может меняться без предупреждения в минорных версиях.
Сбрасывает начальный адрес защиты стека и размер защиты стека состояния потока Python в значения по умолчанию операционной системы.
Пояснение см. в
PyUnstable_ThreadState_SetStackProtection().Добавлено в версии 3.15.
-
PyObject *PyThreadState_GetDict()¶
- Возвращаемое значение: заимствованная ссылка. Часть Stable ABI.
Возвращает словарь, в котором расширения могут хранить информацию о состоянии, специфичном для потока. Каждое расширение должно использовать уникальный ключ для хранения состояния в словаре. Допускается вызов этой функции, когда состояние потока не прикреплено. Если эта функция возвращает
NULLи при этом не было возбуждено исключение, то вызывающий должен считать, что состояние потока не прикреплено.
-
void PyEval_AcquireThread(PyThreadState *tstate)¶
- Часть Stable ABI.
Прикрепляет tstate к текущему потоку, который не должен быть
NULLили уже прикреплён.Вызывающий поток не должен уже иметь прикреплённого состояния потока.
Примечание
Вызов этой функции из потока во время завершения работы среды выполнения приведёт к зависанию потока до выхода программы, даже если поток не был создан Python. Подробнее см. Предостережения относительно завершения интерпретатора.
Изменено в версии 3.8: Функция обновлена для согласованности с
PyEval_RestoreThread(),Py_END_ALLOW_THREADS()иPyGILState_Ensure(), и теперь завершает текущий поток, если вызвана во время завершения работы интерпретатора.Изменено в версии 3.14: При вызове во время завершения работы интерпретатора текущий поток зависает, а не завершается.
PyEval_RestoreThread()– функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).
-
void PyEval_ReleaseThread(PyThreadState *tstate)¶
- Часть Stable ABI.
Открепляет прикреплённое состояние потока. Аргумент tstate, который не должен быть
NULL, используется только для проверки того, что он представляет прикреплённое состояние потока – если это не так, сообщается о фатальной ошибке.PyEval_SaveThread()– функция более высокого уровня, которая всегда доступна (даже если потоки не были инициализированы).
Асинхронные уведомления¶Asynchronous notifications
Предоставляется механизм для асинхронных уведомлений основному потоку интерпретатора. Эти уведомления имеют форму указателя на функцию и аргумента в виде указателя void.
-
int Py_AddPendingCall(int (*func)(void*), void *arg)¶
- Часть Stable ABI.
Планирует вызов функции из основного потока интерпретатора. В случае успеха возвращается
0, и func помещается в очередь для вызова в основном потоке. В случае неудачи возвращается-1без установки какого-либо исключения.При успешной постановке в очередь func будет в конечном итоге вызвана из основного потока интерпретатора с аргументом arg. Она будет вызвана асинхронно по отношению к нормально выполняющемуся коду Python, но при соблюдении обоих этих условий:
на границе байткода;
при удержании основным потоком присоединённого состояния потока (поэтому func может использовать полный C API).
func должна возвращать
0при успехе или-1при неудаче с установленным исключением. func не будет прервана для выполнения другого асинхронного уведомления рекурсивно, но всё же может быть прервана для переключения потоков, если состояние потока отсоединено.Эта функция не требует присоединённого состояния потока. Однако для вызова этой функции в подынтерпретаторе вызывающий должен иметь присоединённое состояние потока. В противном случае функция func может быть запланирована для вызова из неправильного интерпретатора.
Предупреждение
Это низкоуровневая функция, полезная только в особых случаях. Нет гарантии, что func будет вызвана так быстро, насколько это возможно. Если основной поток занят выполнением системного вызова, func не будет вызвана до возврата из системного вызова. Эта функция в целом не подходит для вызова кода Python из произвольных потоков C. Вместо этого используйте
PyThreadState_EnsureFromView().Добавлено в версии 3.1.
Изменено в версии 3.9: Если эта функция вызывается в подынтерпретаторе, функция func теперь планируется для вызова из подынтерпретатора, а не из основного интерпретатора. Каждый подынтерпретатор теперь имеет свой собственный список запланированных вызовов.
Изменено в версии 3.12: Эта функция теперь всегда планирует выполнение func в основном интерпретаторе.
-
int Py_MakePendingCalls(void)¶
- Часть Stable ABI.
Выполняет все отложенные вызовы. Обычно это выполняется автоматически интерпретатором.
Эта функция возвращает
0при успехе и-1с установленным исключением при ошибке.Если эта функция вызывается не в основном потоке главного интерпретатора, она ничего не делает и возвращает
0. Вызывающий должен удерживать присоединённое состояние потока.Добавлено в версии 3.1.
Изменено в версии 3.12: Эта функция выполняет отложенные вызовы только в основном интерпретаторе.
-
int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)¶
- Часть Stable ABI.
Планирует асинхронное возбуждение исключения в потоке. Если в потоке уже было запланировано исключение, оно перезаписывается.
Аргумент id – это идентификатор потока целевого потока, как возвращается
PyThread_get_thread_ident(). exc – это класс возбуждаемого исключения илиNULLдля очистки отложенного исключения (если есть).Возвращает количество затронутых состояний потоков. Обычно это
1, если id найден, даже если никаких изменений не было сделано (заданное exc уже было отложено, или exc равенNULL, но никакое исключение не отложено). Если идентификатор потока не найден, возвращает0. Это не возбуждает исключений.Чтобы предотвратить наивное неправильное использование, необходимо написать собственное расширение C для вызова этой функции. Эта функция должна вызываться с присоединённым состоянием потока. Эта функция не похищает никакие ссылки на exc. Эта функция не обязательно прерывает системные вызовы, такие как
sleep().Изменено в версии 3.7: Тип параметра id изменён с long на unsigned long.
API потоков операционной системы¶Operating system thread APIs
-
PYTHREAD_INVALID_THREAD_ID¶
Страж-значение для недопустимого идентификатора потока.
В настоящее время это эквивалентно
(unsigned long)-1.
-
unsigned long PyThread_start_new_thread(void (*func)(void*), void *arg)¶
- Часть Stable ABI.
Запускает функцию func в новом потоке с аргументом arg. Полученный поток не предназначен для ожидания завершения.
func не должна быть
NULL, но arg может бытьNULL.При успехе эта функция возвращает идентификатор нового потока; при неудаче возвращает
PYTHREAD_INVALID_THREAD_ID.Вызывающий код не должен удерживать присоединённое состояние потока.
-
unsigned long PyThread_get_thread_ident(void)¶
- Часть Stable ABI.
Возвращает идентификатор текущего потока, который никогда не будет равен нулю.
Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать присоединённое состояние потока.
См. также
threading.get_ident()иthreading.Thread.identпредоставляют этот идентификатор в Python.
-
PyObject *PyThread_GetInfo(void)¶
- Часть Stable ABI начиная с версии 3.3.
Получает общую информацию о текущем потоке в виде объекта структурной последовательности. Эта информация доступна как
sys.thread_infoв Python.В случае успеха возвращается новая сильная ссылка на информацию о потоке; в случае неудачи возвращается
NULLс установленным исключением.Вызывающий код должен удерживать присоединённое состояние потока.
-
PY_HAVE_THREAD_NATIVE_ID¶
Этот макрос определён, когда система поддерживает нативные идентификаторы потоков.
-
unsigned long PyThread_get_thread_native_id(void)¶
- Часть Stable ABI на платформах с нативными идентификаторами потоков.
Возвращает нативный идентификатор текущего потока, назначенный ядром операционной системы; это значение никогда не бывает меньше нуля.
Эта функция доступна, только если определён
PY_HAVE_THREAD_NATIVE_ID.Эта функция не может завершиться ошибкой, и вызывающему не нужно удерживать присоединённое состояние потока.
См. также
-
void PyThread_exit_thread(void)¶
- Часть Stable ABI.
Завершает текущий поток. Эта функция обычно считается небезопасной, и её следует избегать. Она сохранена исключительно для обратной совместимости.
Эту функцию безопасно вызывать, только если все функции в полном стеке вызовов написаны так, чтобы допускать это безопасно.
Предупреждение
Если текущая система использует потоки POSIX (также известные как «pthreads»), эта функция вызывает pthread_exit(3), которая пытается развернуть стек и вызвать деструкторы C++ в некоторых реализациях libc. Однако, если достигается функция
noexcept, это может завершить процесс. Другие системы, такие как macOS, выполняют развёртывание.В Windows эта функция вызывает
_endthreadex(), которая уничтожает поток без вызова деструкторов C++.В любом случае существует риск повреждения стека потока.
Устарело с версии 3.14.
-
void PyThread_init_thread(void)¶
- Часть Stable ABI.
Инициализирует API
PyThread*. Python выполняет эту функцию автоматически, поэтому нет особой необходимости вызывать её из расширяющего модуля.
-
int PyThread_set_stacksize(size_t size)¶
- Часть Stable ABI.
Устанавливает размер стека текущего потока в size байт.
Эта функция возвращает
0при успехе,-1, если size некорректен, или-2, если система не поддерживает изменение размера стека. Эта функция не устанавливает исключения.Вызывающий код не должен удерживать присоединённое состояние потока.
-
size_t PyThread_get_stacksize(void)¶
- Часть Stable ABI.
Возвращает размер стека текущего потока в байтах или
0, если используется размер стека по умолчанию для системы.Вызывающий код не должен удерживать присоединённое состояние потока.