# 线程状态和全局解释器锁

除非使用 CPython 的 free-threaded build 版本，否则Python 解释器通常都不是线程安全的。 为了支持多线程的 Python 程序，解释器有一个全局锁，称为 global interpreter lock 或 GIL，线程必须在访问 Python 对象之前先持有它。 如果没有这个锁，即使最简单的操作在多线程的程序中也可能造成问题：例如，当两个线程同时递增同一个对象的引用计数时，引用计数可能只增加一次而不是两次。

因此，线程必须持有 GIL 才能操作 Python 对象或唤起 Python 的 C API。

为了模拟并发，解释器会定期在字节指令间尝试切换线程 (参见 `sys.setswitchinterval()`)。 因此在纯 Python 代码中也必须要有这个锁。

此外，全局解释器锁会在阻塞型 I/O 操作时被释放，如读取或写入文件等。 在 C API 中，这是通过 分离线程状态 完成的。

Python 解释器会将线程的局部信息保存在名为 `PyThreadState` 的数据结构中，或称 thread state。 每个线程都有一个指向 `PyThreadState` 的线程局部指针；这个指针所引用的线程状态会被视为 已附加线程状态。

一个线程在同一时刻只能拥有一个 attached thread state。 已附加线程状态通常等同于持有 GIL，但在自由线程构建中例外。 在启用 GIL 的构建中，附加线程状态会阻塞执行直到 GIL 可以被获取。 不过，即使在禁用 GIL 的构建中，仍然需要拥有已附加线程状态，因为解释器需要记住有哪些线程可以访问 Python 对象。

备注

即使在自由线程构建中，附加线程状态也可能发生阻塞，因为 GIL 可以被重新启用或者线程可能被临时挂起（例如在垃圾回收期间）。

通常，在使用 Python 的 C API 时总是会存在一个已附加线程状态，包括执行嵌入期间和实现方法时，因此你很少会需要自行设置线程状态。 仅在某些特定情况下，例如处于某个 `Py_BEGIN_ALLOW_THREADS` 代码块或全新线程中，线程才没有已附加线程状态。 如果不确定，可检查 `PyThreadState_GetUnchecked()` 是否返回 `NULL`。

如果你确实需要创建线程状态，可以调用 `PyThreadState_New()` 然后再调用 `PyThreadState_Swap()`，或者使用危险的 `PyGILState_Ensure()` 函数。

## 从扩展代码分离线程状态

大多数操作 thread state 的扩展代码具有以下简单结构:

    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
    ... 执行某些阻塞式的 I/O 操作 ...
    Py_END_ALLOW_THREADS

`Py_BEGIN_ALLOW_THREADS` 宏将打开一个新块并声明一个隐藏的局部变量；`Py_END_ALLOW_THREADS` 宏将关闭这个块。

上面的代码块可扩展为下面的代码:

    PyThreadState *_save;

    _save = PyEval_SaveThread();
    ... 执行某些阻塞式的 I/O 操作 ...
    PyEval_RestoreThread(_save);

下面介绍这些函数是如何运作的：

附加线程状态意味着为解释器持有 GIL。 要将其分离，则调用 `PyEval_SaveThread()` 并将结果保存在局部变量中。

通过分离线程状态，GIL 将被释放，以允许其他线程附加到该解释器并执行而让当前线程执行阻塞式 I/O。 当 I/O 操作完成时，可通过调用 `PyEval_RestoreThread()` 重新附加旧线程状态，该函数将等待至 GIL 可被获取。

备注

执行阻塞型 I/O 操作是分离线程状态最常见的使用场景，但它也适用于不需要访问 Python 对象或 Python 的 C API 的长时间运行的原生代码。 例如，标准库 `zlib` 和 `hashlib` 模块会在对数据执行压缩或哈希运算时分离 线程状态。

在 free-threaded build 中，通常不需要考虑 GIL，但是 分离线程状态仍然是需要的，因为解释器需要定期地阻塞所有线程以获取稳定的 Python 对象视图而不会产生竞争条件风险。 例如，CPython 目前会在运行垃圾回收器的时候暂时挂起所有线程。

警告

在解释器最终化期间分离线程状态可能导致非预期的行为。 请参阅 有关运行时最终化的注意事项 了解详情。

### API

以下的宏被使用时通常不带末尾分号；请在 Python 源代码发布包中查看示例用法。

备注

这些宏对于在 free-threaded build 上防止死锁仍然是必要的。

Py_BEGIN_ALLOW_THREADS
  属于 稳定 ABI.

  此宏会扩展为 `{ PyThreadState *_save; _save = PyEval_SaveThread();`。 请注意它包含一个开头花括号；它必须与后面的 `Py_END_ALLOW_THREADS` 宏匹配。有关此宏的进一步讨论请参阅上文。

Py_END_ALLOW_THREADS
  属于 稳定 ABI.

  此宏扩展为 `PyEval_RestoreThread(_save); }`。注意它包含一个右花括号；它必须与之前的 `Py_BEGIN_ALLOW_THREADS` 宏匹配。请参阅上文以进一步讨论此宏。

Py_BLOCK_THREADS
  属于 稳定 ABI.

  这个宏扩展为 `PyEval_RestoreThread(_save);`: 它等价于没有关闭花括号的 `Py_END_ALLOW_THREADS` 宏。

Py_UNBLOCK_THREADS
  属于 稳定 ABI.

  这个宏扩展为 `_save = PyEval_SaveThread();`: 它等价于没有开始花括号和变量声明的 `Py_BEGIN_ALLOW_THREADS` 宏。

## 非 Python 创建的线程

当使用专门的 Python API（如 `threading` 模块）创建线程时，会自动为其关联一个附加线程状态，不过，当线程是从原生代码创建时（例如，由具有自己的线程管理的第三方库创建），它就不会持有附加线程状态。

如果你需要从这些线程调用 Python 代码（这常常会是前述第三方库提供的回调 API 的一部分），你必须先通过新建一个线程状态并附加它来向解释器注册这些线程。

完成这项任务的最可靠方式是通过 `PyThreadState_New()` 加上 `PyThreadState_Swap()`。

备注

`PyThreadState_New` requires an argument pointing to the desired interpreter; such a pointer can be acquired via a call to `PyInterpreterState_Get()` from the code where the thread was created.

例如:

    /* The return value of PyInterpreterState_Get() from the
       function that created this thread. */
    PyInterpreterState *interp = thread_data->interp;

    /* Create a new thread state for the interpreter. It does not start out
       attached. */
    PyThreadState *tstate = PyThreadState_New(interp);

    /* Attach the thread state, which will acquire the GIL. */
    PyThreadState_Swap(tstate);

    /* Perform Python actions here. */
    result = CallSomeFunction();
    /* evaluate result or handle exception */

    /* Destroy the thread state. No Python API allowed beyond this point. */
    PyThreadState_Clear(tstate);
    PyThreadState_DeleteCurrent();

警告

If the interpreter finalized before `PyThreadState_Swap` was called, then `interp` will be a dangling pointer!

## Legacy API

Another common pattern to call Python code from a non-Python thread is to use `PyGILState_Ensure()` followed by a call to `PyGILState_Release()`.

These functions do not work well when multiple interpreters exist in the Python process. If no Python interpreter has ever been used in the current thread (which is common for threads created outside Python), `PyGILState_Ensure` will create and attach a thread state for the "main" interpreter (the first interpreter in the Python process).

Additionally, these functions have thread-safety issues during interpreter finalization. Using `PyGILState_Ensure` during finalization will likely crash the process.

这些函数的用法是这样的:

    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();

    /* 在此执行 Python 动作。 */
    result = CallSomeFunction();
    /* 评估结果或处理异常 */

    /* 释放线程。在此之后不再允许 Python API。 */
    PyGILState_Release(gstate);

## 有关 fork() 的注意事项

有关线程的另一个需要注意的重要问题是它们在面对 C `fork()` 调用时的行为。在大多数支持 `fork()` 的系统中，当一个进程执行 fork 之后将只有发出 fork 的线程存在。这对需要如何处理锁以及 CPython 的运行时内所有的存储状态都会有实质性的影响。

只保留“当前”线程这一事实意味着任何由其他线程所持有的锁永远不会被释放。Python 通过在 fork 之前获取内部使用的锁，并随后释放它们的方式为 `os.fork()` 解决了这个问题。此外，它还会重置子进程中的任何 Lock 对象。在扩展或嵌入 Python 时，没有办法通知 Python 在 fork 之前或之后需要获取或重置的附加（非 Python）锁。需要使用 OS 工具例如 `pthread_atfork()` 来完成同样的事情。此外，在扩展或嵌入 Python 时，直接调用 `fork()` 而不是通过 `os.fork()` (并返回到或调用至 Python 中) 调用可能会导致某个被 fork 之后失效的线程所持有的 Python 内部锁发生死锁。 `PyOS_AfterFork_Child()` 会尝试重置必要的锁，但并不总是能够做到。

所有其他线程都将结束这一事实也意味着 CPython 的运行时状态必须妥善清理，`os.fork()` 就是这样做的。 这意味着最终化归属于当前解释器的所有其他 `PyThreadState` 对象以及所有其他 `PyInterpreterState` 对象。由于这一点以及 "main" 解释器 的特殊性质，`fork()` 应当只在该解释器 的 "main" 线程中被调用，而 CPython 全局运行时最初就是在该线程中初始化的。只有当 `exec()` 将随后立即被调用的情况是唯一的例外。

## 高层级 API

这些是在编写多线程 C 扩展时最常用的类型和函数。

type PyThreadState
  属于 受限 API （作为不透明的结构体）.

  该数据结构代表单个线程的状态。唯一的公有数据成员为：

  PyInterpreterState *interp

    该线程的解释器状态。

void PyEval_InitThreads()
  属于 稳定 ABI.

  不执行任何操作的已弃用函数。

  在 Python 3.6 及更老的版本中，此函数会在 GIL 不存在时创建它。

  在 3.9 版本发生变更: 此函数现在不执行任何操作。

  在 3.7 版本发生变更: 该函数现在由 `Py_Initialize()` 调用，因此你无需再自行调用它。

  在 3.2 版本发生变更: 此函数已不再被允许在 `Py_Initialize()` 之前调用。

  自 3.9 版本弃用.

PyThreadState *PyEval_SaveThread()
  属于 稳定 ABI.

  分离当前线程的 attached thread state 并返回该状态对象。调用此函数返回后，当前线程将不再关联任何 thread state 线程状态。

void PyEval_RestoreThread(PyThreadState *tstate)
  属于 稳定 ABI.

  将 attached thread state 设置为 tstate。传入的 thread state 不应 处于 已附加 状态，否则会导致死锁。调用此函数返回后，tstate 将被附加到当前线程。

  备注

  当运行时处于终结阶段时，若从某个线程调用此函数，该线程将被挂起直至程序退出，即便是由非 Python 创建的线程也不例外。更多详情请参考 有关运行时最终化的注意事项 小节。

  在 3.14 版本发生变更: 如果在解释器处于终结阶段时调用此函数，当前线程将被挂起而非终止。

PyThreadState *PyThreadState_Get()
  属于 稳定 ABI.

  返回当前线程的 attached thread state。如果线程没有已附加的线程状态（例如，当处于 `Py_BEGIN_ALLOW_THREADS` 代码块内部时），则会触发致命错误 (因此调用者无需检查返回值是否为 `NULL` 值)。

  另请参阅 `PyThreadState_GetUnchecked()`。

PyThreadState *PyThreadState_GetUnchecked()

  与 `PyThreadState_Get()` 类似，但如果其为 NULL 则不会杀死进程并设置致命错误。调用方要负责检查结果是否为 NULL 值。

  Added in version 3.13: 在 Python 3.5 到 3.12 中，此函数是私有的并且命名为 `_PyThreadState_UncheckedGet()`。

PyThreadState *PyThreadState_Swap(PyThreadState *tstate)
  属于 稳定 ABI.

  将 attached thread state 设置为 tstate，并返回调用此函数前已附加的 thread state 线程状态。

  此函数在没有 attached thread state 的情况下调用也是安全的；此时它会直接返回 `NULL`，表示之前不存在线程状态。

  参见

  `PyEval_ReleaseThread()`

  备注

  与 `PyGILState_Ensure()` 类似，当运行时处于终结阶段时，调用此函数会导致线程挂起。

## GIL 状态 API

下列函数使用线程级本地存储，并且不能兼容子解释器：

type PyGILState_STATE
  属于 稳定 ABI.

  由 `PyGILState_Ensure()` 返回并传递给 `PyGILState_Release()` 的值的类型。

  enumerator PyGILState_LOCKED

    当调用 `PyGILState_Ensure()` 时 GIL 已经被持有。

  enumerator PyGILState_UNLOCKED

    当调用 `PyGILState_Ensure()` 时 GIL 尚未被持有。

PyGILState_STATE PyGILState_Ensure()
  属于 稳定 ABI.

  确保当前线程可以调用 Python C API，无论 Python 的当前状态或 attached thread state 如何。只要每个调用都与对 `PyGILState_Release()` 的调用相匹配，线程就可以根据需要多次调用此函数。通常，只要线程状态在调用 Release() 之前恢复到其先前状态，就可以在 `PyGILState_Ensure()` 和 `PyGILState_Release()` 调用之间使用其他与线程相关的 API。例如，可以正常使用 `Py_BEGIN_ALLOW_THREADS` 和 `Py_END_ALLOW_THREADS` 宏。

  返回值是一个不透明的"句柄"，指向调用 `PyGILState_Ensure()` 时的 attached thread state，必须将其传递给 `PyGILState_Release()` 以确保 Python 恢复到相同状态。尽管允许递归调用，但这些句柄 不能 共享 — 每次对 `PyGILState_Ensure()` 的独立调用都必须保存其对应的句柄，用于后续调用 `PyGILState_Release()`。

  当此函数返回时，将存在一个 attached thread state，并且线程将能够调用任意 Python 代码。若操作失败则会引发致命错误。

  警告

  当运行时处于终结阶段时调用此函数是不安全的。这样做要么会使线程挂起直至程序结束，在极少数情况下还可能导致解释器完全崩溃。更多详情请参考 有关运行时最终化的注意事项 小节。

  在 3.14 版本发生变更: 如果在解释器处于终结阶段时调用此函数，当前线程将被挂起而非终止。

void PyGILState_Release(PyGILState_STATE)
  属于 稳定 ABI.

  释放之前获取的任何资源。在此调用之后，Python 的状态将与其在对相应 `PyGILState_Ensure()` 调用之前的一样（但是通常此状态对调用方来说将是未知的，对 GILState API 的使用也是如此）。

  对 `PyGILState_Ensure()` 的每次调用都必须与在同一线程上对 `PyGILState_Release()` 的调用相匹配。

PyThreadState *PyGILState_GetThisThreadState()
  属于 稳定 ABI.

  获取当前线程的 attached thread state。如果当前线程尚未使用任何 GILState API，则可能返回 `NULL`。请注意，主线程始终拥有这样的线程状态，即使尚未在主线程上进行任何自动线程状态调用。此函数主要用作辅助/诊断工具。

  备注

  即使在 thread state 已被分离时此函数也可能返回非 `NULL`。大多数情况下建议使用 `PyThreadState_Get()` 或 `PyThreadState_GetUnchecked()`。

  参见

  `PyThreadState_Get()`

int PyGILState_Check()

  如果当前线程持有 GIL 则返回 `1`，否则返回 `0`。此函数可随时从任何线程调用。只有当线程的 线程状态 通过 `PyGILState_Ensure()` 初始化后，它才会返回 `1`。此函数主要用作辅助/诊断工具。例如，在回调函数上下文或内存分配函数中，了解 GIL 是否被锁定可以让调用者执行敏感操作或以不同方式运行时，这个函数就会很有用。

  备注

  如果当前 Python 进程曾经创建过子解释器，则此函数 始终 返回 `1`。在大多数情况下，建议使用 `PyThreadState_GetUnchecked()` 函数。

  Added in version 3.4.

## 低层级 API

PyThreadState *PyThreadState_New(PyInterpreterState *interp)
  属于 稳定 ABI.

  创建一个属于指定解释器对象的新线程状态对象。此操作不需要存在 attached thread state。

void PyThreadState_Clear(PyThreadState *tstate)
  属于 稳定 ABI.

  重置 thread state 对象中的所有信息。 tstate 必须处于 已附加 状态。

  在 3.9 版本发生变更: 此函数现在会调用 `PyThreadState.on_delete` 回调。在之前版本中，此操作是发生在 `PyThreadState_Delete()` 中的。

  在 3.13 版本发生变更: `PyThreadState.on_delete` 回调已被移除。

void PyThreadState_Delete(PyThreadState *tstate)
  属于 稳定 ABI.

  销毁一个 thread state 对象。tstate 不应被 已附加 到任何线程。tstate 必须在之前通过调用 `PyThreadState_Clear()` 进行过重置。

void PyThreadState_DeleteCurrent(void)

  分离 attached thread state (该状态必须已通过先前调用 `PyThreadState_Clear()` 进行重置)，然后销毁它。

  返回时将不会有任何 thread state 处于 已附加 状态。

PyFrameObject *PyThreadState_GetFrame(PyThreadState *tstate)
  属于 稳定 ABI 自 3.10 版起.

  获取 Python 线程状态 tstate 的当前帧。

  返回一个 strong reference。如果没有当前执行的帧则返回 `NULL`。

  另请参阅 `PyEval_GetFrame()`。

  tstate 不得为 `NULL`，并且必须处于 已附加 状态。

  Added in version 3.9.

uint64_t PyThreadState_GetID(PyThreadState *tstate)
  属于 稳定 ABI 自 3.10 版起.

  获取 Python 线程状态 tstate 的唯一 thread state 标识符。

  tstate 不得为 `NULL`，并且必须处于 已附加 状态。

  Added in version 3.9.

PyInterpreterState *PyThreadState_GetInterpreter(PyThreadState *tstate)
  属于 稳定 ABI 自 3.10 版起.

  获取 Python 线程状态 tstate 对应的解释器。

  tstate 不得为 `NULL`，并且必须处于 已附加 状态。

  Added in version 3.9.

void PyThreadState_EnterTracing(PyThreadState *tstate)

  暂停 Python 线程状态 tstate 中的追踪和性能分析。

  使用 `PyThreadState_LeaveTracing()` 函数来恢复它们。

  Added in version 3.11.

void PyThreadState_LeaveTracing(PyThreadState *tstate)

  恢复 Python 线程状态 tstate 中被 `PyThreadState_EnterTracing()` 函数暂停的追踪和性能分析。

  另请参阅 `PyEval_SetTrace()` 和 `PyEval_SetProfile()` 函数。

  Added in version 3.11.

int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size)
  这是 不稳定 API。它可能在次要版本中不经警告地被更改。

  设置一个 Python 线程状态的栈保护起始地址和栈保护大小。

  成功时，返回 `0`。失败时，设置一个异常并返回 `-1`。

  CPython 通过在注意到机器的执行栈即将溢出时引发 `RecursionError` 实现针对 C 代码的 递归控制。请查看 `Py_EnterRecursiveCall()` 函数的示例。为此，需要知道当前线程栈的位置，这通常是从操作系统获取的。例如当使用 Boost 库的 `boost::context` 之类的上下文切换技术使栈发生改变时，你必须调用 `PyUnstable_ThreadState_SetStackProtection()` 将变化通知给 CPython。

  在修改栈之前或之后调用 `PyUnstable_ThreadState_SetStackProtection()`。 不要在调用和栈修改之间调用任何其他 Python C API。

  请参阅 `PyUnstable_ThreadState_ResetStackProtection()` 了解如何撤销此操作。

  Added in version 3.15.

void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)
  这是 不稳定 API。它可能在次要版本中不经警告地被更改。

  将一个 Python 线程状态的栈保护起始地址和栈保护大小重置为操作系统的默认值。

  请参阅 `PyUnstable_ThreadState_SetStackProtection()` 查看相关说明。

  Added in version 3.15.

PyObject *PyThreadState_GetDict()
  返回值：借入的引用。 属于 稳定 ABI.

  返回一个字典，扩展模块可在其中存储线程特定的状态信息。每个扩展模块应使用唯一的键来在此字典中存储状态。当没有 thread state 处于 已附加 状态时，调用此函数是安全的。如果此函数返回 `NULL`，则表示没有引发异常，调用者应假定没有线程状态被附加。

void PyEval_AcquireThread(PyThreadState *tstate)
  属于 稳定 ABI.

  将 tstate 附加 到当前线程，当前线程不能为 `NULL` 或者已经 附加线程状态。

  调用方线程不能已经具有 attached thread state。

  备注

  当运行时处于终结阶段时，若从某个线程调用此函数，该线程将被挂起直至程序退出，即便是由非 Python 创建的线程也不例外。更多详情请参考 有关运行时最终化的注意事项 小节。

  在 3.8 版本发生变更: 已被更新为与 `PyEval_RestoreThread()`, `Py_END_ALLOW_THREADS()` 和 `PyGILState_Ensure()` 保持一致，如果在解释器正在最终化时被调用则会终结当前线程。

  在 3.14 版本发生变更: 如果在解释器处于终结阶段时调用此函数，当前线程将被挂起而非终止。

  `PyEval_RestoreThread()` 是一个始终可用的（即使线程尚未初始化）更高层级函数。

void PyEval_ReleaseThread(PyThreadState *tstate)
  属于 稳定 ABI.

  分离 attached thread state。 tstate 参数必须不为 `NULL`，该参数仅被用于检查它是否代表 attached thread state --- 如果不是，则会报告一个致命级错误。

  `PyEval_SaveThread()` 是一个始终可用的（即使线程尚未初始化）更高层级函数。

# 异步通知

提供了一种向主解释器线程发送异步通知的机制。这些通知将采用函数指针和空指针参数的形式。

int Py_AddPendingCall(int (*func)(void*), void *arg)
  属于 稳定 ABI.

  将一个函数加入从主解释器线程调用的计划任务。成功时，将返回 `0` 并将 func 加入要被主线程调用的等待队列。失败时，将返回 `-1` 但不会设置任何异常。

  当成功加入队列后，func 将 最终 附带参数 arg 被主解释器线程调用。对于正常运行的 Python 代码来说它将被异步地调用，但要同时满足以下两个条件：

  - 位于 bytecode 的边界上；

  - 主线程持有一个 attached thread state (因此 func 可以使用完整的 C API)。

  func 必须在成功时返回 `0`，或在失败时返回 `-1` 并设置一个异常。 func 不会被中断来递归地执行另一个异步通知，但如果 thread state 已被分离则它仍可被中断以切换线程。

  此函数不需要 attached thread state。不过，要在子解释器中调用此函数，调用方必须具有 attached thread state。否则，函数 func 可能会被安排给错误的解释器来调用。

  警告

  这是一个低层级函数，只在非常特殊的情况下有用。不能保证 func 会尽快被调用。如果主线程忙于执行某个系统调用，func 将不会在系统调用返回之前被调用。此函数 通常 不适合 从任意 C 线程调用 Python 代码。作为替代，请使用 PyGILState API 文档。

  Added in version 3.1.

  在 3.9 版本发生变更: 如果此函数在子解释器中被调用，则函数 func 将被安排在子解释器中调用，而不是在主解释器中调用。现在每个子解释器都有自己的计划调用列表。

  在 3.12 版本发生变更: 此函数现在总是会安排 func 在主解释器中运行。

int Py_MakePendingCalls(void)
  属于 稳定 ABI.

  执行所有待命的调用。这通常会由解释器自动执行。

  此函数成功时返回 `0`，失败时返回 `-1` 并设置一个异常。

  如果此函数不是在主解释器的主线程中被调用，它将不做任何事并返回 `0`。调用方必须持有 attached thread state 线程状态。

  Added in version 3.1.

  在 3.12 版本发生变更: 此函数将只在主解释器中运行待命的调用。

int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
  属于 稳定 ABI.

  在一个线程中异步引发异常。id 参数是目标线程的线程 ID；exc 是要引发的异常对象。此函数不会窃取对 exc 的引用。 为防止误用，必须编写自己的 C 扩展来调用此函数。必须在 attached thread state 下调用此函数。 返回被修改的线程状态数量；通常为 1，如果找不到线程 ID 则返回 0。如果 exc 为 `NULL`，则清除该线程的待处理异常（如果有）。 此函数不会引发任何异常。

  在 3.7 版本发生变更: id 形参的类型已从 long 变为 unsigned long。

# 操作系统线程 API

PYTHREAD_INVALID_THREAD_ID

  代表无效线程 ID 的哨兵值。

  该值目前等于 `(unsigned long)-1`。

unsigned long PyThread_start_new_thread(void (*func)(void*), void *arg)
  属于 稳定 ABI.

  在新线程中启动函数 func 并传入参数 arg。结果线程将不被合并。

  func 不可为 `NULL`，但 arg 可以为 `NULL`。

  成功时，此函数将返回新线程的标识号；失败时，将返回 `PYTHREAD_INVALID_THREAD_ID`。

  调用方不需要持有 attached thread state。

unsigned long PyThread_get_thread_ident(void)
  属于 稳定 ABI.

  返回当前线程的标识号，它一定不为零。

  此函数不会执行失败，并且调用方不需要持有 attached thread state。

  参见

  `threading.get_ident()`

PyObject *PyThread_GetInfo(void)
  属于 稳定 ABI 自 3.3 版起.

  获取有关当前线程的 结构体序列 对象形式的基本信息。此信息可在 Python 中作为 `sys.thread_info` 访问。

  成功时，此函数将返回一个指向线程信息的新的 strong reference；失败时，将返回 `NULL` 并设置一个异常。

  调用方必须持有一个 attached thread state。

PY_HAVE_THREAD_NATIVE_ID

  该宏将在系统支持原生线程 ID 时被定义。

unsigned long PyThread_get_thread_native_id(void)
  属于 稳定 ABI on platforms with native thread IDs.

  获取当前线程由操作系统的内核所分配的原生标识号，它绝对不会小于零。

  此函数仅在定义了 `PY_HAVE_THREAD_NATIVE_ID` 时可用。

  此函数不会执行失败，并且调用方不需要持有 attached thread state。

  参见

  `threading.get_native_id()`

void PyThread_exit_thread(void)
  属于 稳定 ABI.

  终结当前线程。此函数通常被视为是不安全的并应避免使用。它只是为了向下兼容而被保留。

  此函数仅在整个调用栈中的所有函数都被编写为能够安全地支持它时才能被安全地调用。

  警告

  如果当前系统使用 POSIX 线程（或称“p 线程”），此函数将调用 pthread_exit(3)，它会尝试展开栈并在某些 libc 实现上调用 C++ 析构器，如果抵达一个 `noexcept` 函数，它可能会终结进程。在其他系统，如 macOS 上，只执行展开。

  在 Windows 上，此函数将调用 `_endthreadex()`，它将杀掉线程而不调用 C++ 析构器。

  在任何情况下，都存在线程栈损坏的风险。

  自 3.14 版本弃用.

void PyThread_init_thread(void)
  属于 稳定 ABI.

  初始化 `PyThread*` API。Python 会自动执行此函数，因此很少需要从扩展模块调用它。

int PyThread_set_stacksize(size_t size)
  属于 稳定 ABI.

  将当前线程的栈大小设为 size 个字节。

  此函数成功时返回 `0`，如果 size 无效则返回 `-1`，或者如果系统不支持修改栈大小则返回 `-2`。此函数不会设置异常。

  调用方不需要持有 attached thread state。

size_t PyThread_get_stacksize(void)
  属于 稳定 ABI.

  返回以字节为单位的当前线程栈大小，或者如果是使用系统的默认栈大小则返回 `0`。

  调用方不需要持有 attached thread state。