同步原语
********

C-API 提供了一个基本的互斥锁。

type PyMutex

   一个互斥锁。 "PyMutex" 应当被初始化为零以代表未加锁状态。例如:

      PyMutex mutex = {0};

   "PyMutex" 的实例不应被拷贝或移动。 "PyMutex" 的内容和地址都是有意义
   的，它必须在内存中保持一个固定的、可写的位置。

   备注:

     "PyMutex" 目前占用一个字节，但这个大小应当被视为是不稳定的。这个
     大小可能在未来的 Python 发布版中发生改变而不会设置弃用期。

   Added in version 3.13.

void PyMutex_Lock(PyMutex *m)
    * Thread safety: Atomic.*

   锁定互斥锁 *m*。如果另一个线程已经锁定了它，调用方线程将会阻塞直到
   互斥锁被解锁。在阻塞期间，如果线程存在 *线程状态* 则会临时释放它。

   Added in version 3.13.

void PyMutex_Unlock(PyMutex *m)
    * Thread safety: Atomic.*

   解锁互斥锁 *m*。该互斥锁必须已被锁定 --- 否则，此函数将发生致命错误
   。

   Added in version 3.13.

int PyMutex_IsLocked(PyMutex *m)
    * Thread safety: Atomic.*

   若互斥锁 *m* 当前处于锁定状态，则返回非零值；否则返回零。

   备注:

     此函数仅适用于断言和调试场景，请勿将其用于并发控制决策，因为锁状
     态可能在检查后立即发生变化。

   Added in version 3.14.


Python 关键节 API
=================

此关键节 API 为 *自由线程* CPython 的每对象锁之上提供了一个死锁避免层
。它们旨在替代对 *global interpreter lock* 的依赖，而在具有全局解释器
锁的 Python 版本上将不做任何操作。

关键节被设计用于在 C-API 扩展中实现的自定义类型。它们通常不应当被用于
内置类型如 "list" 和 "dict" 因为它们的公有 C-API 已经在内部使用了关键
节，一个显著的例外是 "PyDict_Next()"，它需要在外部获取关键节。

关键节是通过隐式地挂起活动关键节来避免死锁的，因此，它们并不提供传统锁
如 "PyMutex" 所提供的那种独占访问。 当一个关键节启动时，将会获取对象的
每对象锁。如果关键节内部执行的代码调用了 C-API 函数那么它可以挂起关键
节从而释放这个每对象锁，这样其他线程就可以获取同一个对象的每对象锁。

此外，还提供了接受 "PyMutex" 指针（而非 Python 对象）的函数变体。当你
处于没有 "PyObject" 的场景中时（例如，处理一个既未继承也未封装
"PyObject" 的 C 类型，但仍需以可能导致死锁的方式调用 C API），请使用这
些变体来启动临界区。

宏所使用的函数和结构体是针对 C 宏不可用的场景而公开的。它们应当仅被用
于给定的宏扩展中。请注意这些结构体的大小和内容在未来的 Python 版本中可
能发生改变。

备注:

  需要同时锁定两个对象的操作必须使用 "Py_BEGIN_CRITICAL_SECTION2"。你
  *不可* 使用嵌套的关键节来同时锁定一个以上的对象，因为内层的关键节可
  能会挂起外层的关键节。这个 API 没有提供同时锁定两个以上对象的办法。

用法示例:

   static PyObject *
   set_field(MyObject *self, PyObject *value)
   {
      Py_BEGIN_CRITICAL_SECTION(self);
      Py_SETREF(self->field, Py_XNewRef(value));
      Py_END_CRITICAL_SECTION();
      Py_RETURN_NONE;
   }

在上面的例子中，"Py_SETREF" 调用了 "Py_DECREF"，它可以通过一个对象的取
消分配函数来调用任意代码。当由最终化器触发的代码发生阻塞并调用
"PyEval_SaveThread()" 时关键节 API 将通过允许运行临时挂起关键节来避免
由于重入和锁顺序导致的潜在死锁。

Py_BEGIN_CRITICAL_SECTION(op)

   为对象 *op* 获取每对象锁并开始一个关键节。

   在自由线程构建版中，该宏将扩展为:

      {
          PyCriticalSection _py_cs;
          PyCriticalSection_Begin(&_py_cs, (PyObject*)(op))

   在默认构建版中，该宏将扩展为 "{"。

   Added in version 3.13.

Py_BEGIN_CRITICAL_SECTION_MUTEX(m)

   锁定互斥锁 *m* 并开始一个临界区。

   在自由线程构建版中，该宏将扩展为:

      {
           PyCriticalSection _py_cs;
           PyCriticalSection_BeginMutex(&_py_cs, m)

   需要注意的是，与 "Py_BEGIN_CRITICAL_SECTION" 不同，此宏的参数无需类
   型转换——它必须是一个 "PyMutex" 指针。

   在默认构建版中，该宏将扩展为 "{"。

   Added in version 3.14.

Py_END_CRITICAL_SECTION()

   结束关键节并释放每对象锁。

   在自由线程构建版中，该宏将扩展为:

          PyCriticalSection_End(&_py_cs);
      }

   在默认构建版中，该宏将扩展为 "}"。

   Added in version 3.13.

Py_BEGIN_CRITICAL_SECTION2(a, b)

   为对象 *a* 和 *b* 获取每对象锁并开始一个关键节。 这些锁将按一致的顺
   序获取（最低的地址在最前）以避免锁排序死锁。

   在自由线程构建版中，该宏将扩展为:

      {
          PyCriticalSection2 _py_cs2;
          PyCriticalSection2_Begin(&_py_cs2, (PyObject*)(a), (PyObject*)(b))

   在默认构建版中，该宏将扩展为 "{"。

   Added in version 3.13.

Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2)

   锁定互斥锁 *m1* 和 *m2* 并开始一个临界区。

   在自由线程构建版中，该宏将扩展为:

      {
           PyCriticalSection2 _py_cs2;
           PyCriticalSection2_BeginMutex(&_py_cs2, m1, m2)

   需要注意的是，与 "Py_BEGIN_CRITICAL_SECTION2" 不同，此宏的参数无需
   类型转换——它们必须是 "PyMutex" 指针。

   在默认构建版中，该宏将扩展为 "{"。

   Added in version 3.14.

Py_END_CRITICAL_SECTION2()

   结束关键节并释放每对象锁。

   在自由线程构建版中，该宏将扩展为:

          PyCriticalSection2_End(&_py_cs2);
      }

   在默认构建版中，该宏将扩展为 "}"。

   Added in version 3.13.


旧式加锁 API
============

这些 API 自 Python 3.13 起已随 "PyMutex" 的引入而过时。

type PyThread_type_lock

   一个指向互斥锁的指针。

type PyLockStatus

   附带超时获取锁操作的结果。

   enumerator PY_LOCK_FAILURE

      获取锁失败。

   enumerator PY_LOCK_ACQUIRED

      锁已被成功获取。

   enumerator PY_LOCK_INTR

      锁被一个信号中断。

PyThread_type_lock PyThread_allocate_lock(void)
    * 属于 稳定 ABI.*

   分配一个新锁。

   成功时，此函数将返回一个锁；失败时，此函数将返回 "0" 且不设置异常。

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

void PyThread_free_lock(PyThread_type_lock lock)
    * 属于 稳定 ABI.*

   销毁 *lock*。在调用此函数时该锁不应被任何线程持有。

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

PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag)
    * 属于 稳定 ABI.*

   获取 *lock* 并附带超时控制。

   此函数将等待 *microseconds* 微秒以获取锁。如果达到超时限制，此函数
   将返回 "PY_LOCK_FAILURE"。如果 *microseconds* 为 "-1"，它将无限等待
   直到锁被释放。

   如果 *intr_flag* 为 "1"，获取锁可能会被信号中断，在这种情况下此函数
   将返回 "PY_LOCK_INTR"。当被中断时，通常会预期调用方将执行对
   "Py_MakePendingCalls()" 的调用以将一个异常传播给 Python 代码。

   如果锁被成功获取，此函数将返回 "PY_LOCK_ACQUIRED"。

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

int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
    * 属于 稳定 ABI.*

   获取 *lock*。

   如果 *waitflag* 为 "1" 且另一个线程目前持有锁，此函数将等待直到锁可
   被获取并将始终返回 "1"。

   如果 *waitflag* 为 "0" 且另一个线程持有锁，此函数将不会等待而是返回
   "0"。如果锁未被另一个线程持有，则此函数将获取它并返回 "1"。

   不同于 "PyThread_acquire_lock_timed()"，获取锁不会被信号中断。

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

int PyThread_release_lock(PyThread_type_lock lock)
    * 属于 稳定 ABI.*

   释放 *lock*。如果 *lock* 未被持有，则此函数将引发致命错误。

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